diff --git a/build/lib/eslint/code-import-patterns.ts b/.eslintplugin/code-import-patterns.ts similarity index 98% rename from build/lib/eslint/code-import-patterns.ts rename to .eslintplugin/code-import-patterns.ts index 72b63a45b35..c9a24c849d7 100644 --- a/build/lib/eslint/code-import-patterns.ts +++ b/.eslintplugin/code-import-patterns.ts @@ -6,10 +6,10 @@ import * as eslint from 'eslint'; import { TSESTree } from '@typescript-eslint/experimental-utils'; import * as path from 'path'; -import * as minimatch from 'minimatch'; +import minimatch from 'minimatch'; import { createImportRuleListener } from './utils'; -const REPO_ROOT = path.normalize(path.join(__dirname, '../../../')); +const REPO_ROOT = path.normalize(path.join(__dirname, '../')); interface ConditionalPattern { when?: 'hasBrowser' | 'hasNode' | 'test'; diff --git a/build/lib/eslint/code-layering.ts b/.eslintplugin/code-layering.ts similarity index 100% rename from build/lib/eslint/code-layering.ts rename to .eslintplugin/code-layering.ts diff --git a/build/lib/eslint/code-no-look-behind-regex.ts b/.eslintplugin/code-no-look-behind-regex.ts similarity index 100% rename from build/lib/eslint/code-no-look-behind-regex.ts rename to .eslintplugin/code-no-look-behind-regex.ts diff --git a/build/lib/eslint/code-no-nls-in-standalone-editor.ts b/.eslintplugin/code-no-nls-in-standalone-editor.ts similarity index 100% rename from build/lib/eslint/code-no-nls-in-standalone-editor.ts rename to .eslintplugin/code-no-nls-in-standalone-editor.ts diff --git a/build/lib/eslint/code-no-standalone-editor.ts b/.eslintplugin/code-no-standalone-editor.ts similarity index 100% rename from build/lib/eslint/code-no-standalone-editor.ts rename to .eslintplugin/code-no-standalone-editor.ts diff --git a/build/lib/eslint/code-no-test-only.ts b/.eslintplugin/code-no-test-only.ts similarity index 100% rename from build/lib/eslint/code-no-test-only.ts rename to .eslintplugin/code-no-test-only.ts diff --git a/build/lib/eslint/code-no-unexternalized-strings.ts b/.eslintplugin/code-no-unexternalized-strings.ts similarity index 100% rename from build/lib/eslint/code-no-unexternalized-strings.ts rename to .eslintplugin/code-no-unexternalized-strings.ts diff --git a/build/lib/eslint/code-no-unused-expressions.ts b/.eslintplugin/code-no-unused-expressions.ts similarity index 100% rename from build/lib/eslint/code-no-unused-expressions.ts rename to .eslintplugin/code-no-unused-expressions.ts diff --git a/build/lib/eslint/code-translation-remind.ts b/.eslintplugin/code-translation-remind.ts similarity index 100% rename from build/lib/eslint/code-translation-remind.ts rename to .eslintplugin/code-translation-remind.ts diff --git a/.eslintplugin/index.js b/.eslintplugin/index.js new file mode 100644 index 00000000000..9f45316837a --- /dev/null +++ b/.eslintplugin/index.js @@ -0,0 +1,12 @@ +const glob = require('glob'); +const path = require('path'); + +require('ts-node').register({ experimentalResolver: true, transpileOnly: true }); + +// Re-export all .ts files as rules +const rules = {}; +glob.sync(`${__dirname}/*.ts`).forEach((file) => { + rules[path.basename(file, '.ts')] = require(file); +}); + +exports.rules = rules; diff --git a/.eslintplugin/tsconfig.json b/.eslintplugin/tsconfig.json new file mode 100644 index 00000000000..0da715fd036 --- /dev/null +++ b/.eslintplugin/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es2020", + "lib": [ + "ES2020" + ], + "module": "commonjs", + "esModuleInterop": true, + "alwaysStrict": true, + "allowJs": true, + "strict": true, + "exactOptionalPropertyTypes": false, + "useUnknownInCatchVariables": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "newLine": "lf", + "noEmit": true + }, + "include": [ + "**/*.ts", + "**/*.js" + ], + "exclude": [ + "node_modules/**" + ] +} diff --git a/build/lib/eslint/utils.ts b/.eslintplugin/utils.ts similarity index 100% rename from build/lib/eslint/utils.ts rename to .eslintplugin/utils.ts diff --git a/build/lib/eslint/vscode-dts-cancellation.ts b/.eslintplugin/vscode-dts-cancellation.ts similarity index 100% rename from build/lib/eslint/vscode-dts-cancellation.ts rename to .eslintplugin/vscode-dts-cancellation.ts diff --git a/build/lib/eslint/vscode-dts-create-func.ts b/.eslintplugin/vscode-dts-create-func.ts similarity index 100% rename from build/lib/eslint/vscode-dts-create-func.ts rename to .eslintplugin/vscode-dts-create-func.ts diff --git a/build/lib/eslint/vscode-dts-event-naming.ts b/.eslintplugin/vscode-dts-event-naming.ts similarity index 96% rename from build/lib/eslint/vscode-dts-event-naming.ts rename to .eslintplugin/vscode-dts-event-naming.ts index 956ba346087..5e767c6e257 100644 --- a/build/lib/eslint/vscode-dts-event-naming.ts +++ b/.eslintplugin/vscode-dts-event-naming.ts @@ -88,11 +88,10 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule { if (def.type === AST_NODE_TYPES.Identifier) { return def; - } else if ((def.type === AST_NODE_TYPES.TSPropertySignature || def.type === AST_NODE_TYPES.Property) && def.key.type === AST_NODE_TYPES.Identifier) { + } else if ((def.type === AST_NODE_TYPES.TSPropertySignature || def.type === AST_NODE_TYPES.PropertyDefinition) && def.key.type === AST_NODE_TYPES.Identifier) { return def.key; } return this.getIdent(def.parent); } }; - diff --git a/build/lib/eslint/vscode-dts-interface-naming.ts b/.eslintplugin/vscode-dts-interface-naming.ts similarity index 100% rename from build/lib/eslint/vscode-dts-interface-naming.ts rename to .eslintplugin/vscode-dts-interface-naming.ts diff --git a/build/lib/eslint/vscode-dts-literal-or-types.ts b/.eslintplugin/vscode-dts-literal-or-types.ts similarity index 100% rename from build/lib/eslint/vscode-dts-literal-or-types.ts rename to .eslintplugin/vscode-dts-literal-or-types.ts diff --git a/build/lib/eslint/vscode-dts-provider-naming.ts b/.eslintplugin/vscode-dts-provider-naming.ts similarity index 100% rename from build/lib/eslint/vscode-dts-provider-naming.ts rename to .eslintplugin/vscode-dts-provider-naming.ts diff --git a/build/lib/eslint/vscode-dts-region-comments.ts b/.eslintplugin/vscode-dts-region-comments.ts similarity index 100% rename from build/lib/eslint/vscode-dts-region-comments.ts rename to .eslintplugin/vscode-dts-region-comments.ts diff --git a/build/lib/eslint/vscode-dts-use-thenable.ts b/.eslintplugin/vscode-dts-use-thenable.ts similarity index 100% rename from build/lib/eslint/vscode-dts-use-thenable.ts rename to .eslintplugin/vscode-dts-use-thenable.ts diff --git a/build/lib/eslint/vscode-dts-vscode-in-comments.ts b/.eslintplugin/vscode-dts-vscode-in-comments.ts similarity index 100% rename from build/lib/eslint/vscode-dts-vscode-in-comments.ts rename to .eslintplugin/vscode-dts-vscode-in-comments.ts diff --git a/.eslintrc.json b/.eslintrc.json index 4d49a16fbf0..3ad6a748650 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,7 +8,8 @@ "plugins": [ "@typescript-eslint", "jsdoc", - "header" + "header", + "local" ], "rules": { "constructor-super": "warn", @@ -61,17 +62,17 @@ ] } ], - "code-no-unused-expressions": [ + "local/code-no-unused-expressions": [ "warn", { "allowTernary": true } ], - "code-translation-remind": "warn", - "code-no-nls-in-standalone-editor": "warn", - "code-no-standalone-editor": "warn", - "code-no-unexternalized-strings": "warn", - "code-layering": [ + "local/code-translation-remind": "warn", + "local/code-no-nls-in-standalone-editor": "warn", + "local/code-no-standalone-editor": "warn", + "local/code-no-unexternalized-strings": "warn", + "local/code-layering": [ "warn", { "common": [], @@ -122,8 +123,8 @@ "**/*.test.ts" ], "rules": { - "code-no-test-only": "error", - "code-no-unexternalized-strings": "off" + "local/code-no-test-only": "error", + "local/code-no-unexternalized-strings": "off" } }, { @@ -132,14 +133,14 @@ "**/vscode.proposed.*.d.ts" ], "rules": { - "vscode-dts-create-func": "warn", - "vscode-dts-literal-or-types": "warn", - "vscode-dts-interface-naming": "warn", - "vscode-dts-cancellation": "warn", - "vscode-dts-use-thenable": "warn", - "vscode-dts-region-comments": "warn", - "vscode-dts-vscode-in-comments": "warn", - "vscode-dts-provider-naming": [ + "local/vscode-dts-create-func": "warn", + "local/vscode-dts-literal-or-types": "warn", + "local/vscode-dts-interface-naming": "warn", + "local/vscode-dts-cancellation": "warn", + "local/vscode-dts-use-thenable": "warn", + "local/vscode-dts-region-comments": "warn", + "local/vscode-dts-vscode-in-comments": "warn", + "local/vscode-dts-provider-naming": [ "warn", { "allowed": [ @@ -154,7 +155,7 @@ ] } ], - "vscode-dts-event-naming": [ + "local/vscode-dts-event-naming": [ "warn", { "allowed": [ @@ -200,8 +201,8 @@ "src/**/*.ts" ], "rules": { - "code-no-look-behind-regex": "warn", - "code-import-patterns": [ + "local/code-no-look-behind-regex": "warn", + "local/code-import-patterns": [ "warn", { // imports that are allowed in all files of layers: @@ -210,8 +211,7 @@ // - electron-browser "when": "hasBrowser", "allow": [ - "vs/css!./**/*", - "@microsoft/applicationinsights-web" + "vs/css!./**/*" ] }, { @@ -226,7 +226,6 @@ "@vscode/vscode-languagedetection", "@vscode/ripgrep", "@vscode/iconv-lite-umd", - "applicationinsights", "assert", "child_process", "console", @@ -261,6 +260,7 @@ "windows-process-tree", "worker_threads", "xterm", + "xterm-addon-canvas", "xterm-addon-search", "xterm-addon-serialize", "xterm-addon-unicode11", @@ -537,7 +537,7 @@ ] }, { - "target": "src/vs/workbench/{workbench.sandbox.main.ts,workbench.desktop.sandbox.main.ts}", + "target": "src/vs/workbench/workbench.desktop.main.ts", "layer": "electron-sandbox", "restrictions": [ "vs/base/*/~", @@ -550,26 +550,7 @@ "vs/workbench/api/~", "vs/workbench/services/*/~", "vs/workbench/contrib/*/~", - "vs/workbench/workbench.common.main", - "vs/workbench/workbench.sandbox.main" - ] - }, - { - "target": "src/vs/workbench/workbench.desktop.main.ts", - "layer": "electron-browser", - "restrictions": [ - "vs/base/*/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/editor/editor.all", - "vs/workbench/~", - "vs/workbench/api/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - "vs/workbench/workbench.common.main", - "vs/workbench/workbench.sandbox.main" + "vs/workbench/workbench.common.main" ] }, { @@ -596,7 +577,7 @@ "test/**/*.ts" ], "rules": { - "code-import-patterns": [ + "local/code-import-patterns": [ "warn", { "target": "test/smoke/**", diff --git a/.github/commands.json b/.github/commands.json index 68a50baae95..c429bff29f2 100644 --- a/.github/commands.json +++ b/.github/commands.json @@ -11,34 +11,51 @@ "action": "updateLabels", "addLabel": "*question" }, + { + "type": "comment", + "name": "dev-question", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "updateLabels", + "addLabel": "*dev-question" + }, { "type": "label", "name": "*question", "action": "close", + "reason": "not_planned", "comment": "We closed this issue because it is a question about using VS Code rather than an issue or feature request. Please search for help on [StackOverflow](https://aka.ms/vscodestackoverflow), where the community has already answered thousands of similar questions. You may find their [guide on asking a new question](https://aka.ms/vscodestackoverflowquestion) helpful if your question has not already been asked. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting).\n\nHappy Coding!" }, { "type": "label", "name": "*dev-question", "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!" + "reason": "not_planned", + "comment": "We have a great extension developer community over on [GitHub discussions](https://github.com/microsoft/vscode-discussions/discussions) and [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", "action": "close", + "reason": "not_planned", "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 guidelines](https://aka.ms/vscodeissuereporting).\n\nHappy Coding!" }, { "type": "label", "name": "*not-reproducible", "action": "close", + "reason": "not_planned", "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 guidelines](https://aka.ms/vscodeissuereporting) might help you with that.\n\nHappy Coding!" }, { "type": "label", "name": "*out-of-scope", "action": "close", + "reason": "not_planned", "comment": "We closed this issue because we [don't plan to address it](https://aka.ms/vscode-out-of-scope) in the foreseeable future. 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 guidelines](https://aka.ms/vscodeissuereporting).\n\nThanks for your understanding, and happy coding!" }, { @@ -57,12 +74,14 @@ "type": "label", "name": "*caused-by-extension", "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 guidelines](https://aka.ms/vscodeissuereporting).\n\nHappy Coding!" + "reason": "not_planned", + "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 guidelines](https://aka.ms/vscodeissuereporting). If you don't know which extension is causing the problem, you can run `Help: Start extension bisect` from the command palette (F1) to help identify the problem extension.\n\nHappy Coding!" }, { "type": "label", "name": "*as-designed", "action": "close", + "reason": "not_planned", "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 guidelines](https://aka.ms/vscodeissuereporting).\n\nHappy Coding!" }, { @@ -104,6 +123,7 @@ "type": "label", "name": "*duplicate", "action": "close", + "reason": "not_planned", "comment": "Thanks for creating this issue! We figured it's covering the same as another one we already have. Thus, we closed this one as a duplicate. You can search for [similar existing issues](${duplicateQuery}). See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting).\n\nHappy Coding!" }, { @@ -154,7 +174,7 @@ "IllusionMH" ], "action": "updateLabels", - "addLabel": "~needs more info" + "addLabel": "~info-needed" }, { "type": "comment", @@ -165,14 +185,14 @@ "gjsjohnmurray", "IllusionMH" ], - "addLabel": "needs more info", + "addLabel": "info-needed", "comment": "Thanks for creating this issue regarding performance! Please follow this guide to help us diagnose performance issues: https://github.com/microsoft/vscode/wiki/Performance-Issues \n\nHappy Coding!" }, { "type": "comment", "name": "jsDebugLogs", "action": "updateLabels", - "addLabel": "needs more info", + "addLabel": "info-needed", "comment": "Please collect trace logs using the following instructions:\n\n> If you're able to, add `\"trace\": true` to your `launch.json` and reproduce the issue. The location of the log file on your disk will be written to the Debug Console. Share that with us.\n>\n> ⚠️ This log file will not contain source code, but will contain file paths. You can drop it into https://microsoft.github.io/vscode-pwa-analyzer/index.html to see what it contains. If you'd rather not share the log publicly, you can email it to connor@xbox.com" }, { @@ -185,22 +205,23 @@ "IllusionMH" ], "action": "close", + "reason": "completed", "addLabel": "unreleased" }, { "type": "label", - "name": "~needs more info", + "name": "~info-needed", "action": "updateLabels", - "addLabel": "needs more info", - "removeLabel": "~needs more info", + "addLabel": "info-needed", + "removeLabel": "~info-needed", "comment": "Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our [issue reporting guidelines](https://aka.ms/vscodeissuereporting). Please take the time to review these and update the issue.\n\nHappy Coding!" }, { "type": "label", - "name": "~needs version info", + "name": "~version-info-needed", "action": "updateLabels", - "addLabel": "needs more info", - "removeLabel": "~needs version info", + "addLabel": "info-needed", + "removeLabel": "~version-info-needed", "comment": "Thanks for creating this issue! We figured it's missing some basic information, such as a version number, or in some other way doesn't follow our [issue reporting guidelines](https://aka.ms/vscodeissuereporting). Please take the time to review these and update the issue.\n\nHappy Coding!" }, { @@ -222,6 +243,7 @@ "type": "label", "name": "*off-topic", "action": "close", + "reason": "not_planned", "comment": "Thanks for creating this issue. We think this issue is unactionable or unrelated to the goals of this project. Please follow our [issue reporting guidelines](https://aka.ms/vscodeissuereporting).\n\nHappy Coding!" }, { @@ -234,6 +256,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the Python extension. Please file the issue to the [Python extension repository](https://github.com/microsoft/vscode-python). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -247,6 +270,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the Jupyter extension. Please file the issue to the [Jupyter extension repository](https://github.com/microsoft/vscode-jupyter). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -260,6 +284,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the C extension. Please file the issue to the [C extension repository](https://github.com/microsoft/vscode-cpptools). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -273,6 +298,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the C++ extension. Please file the issue to the [C++ extension repository](https://github.com/microsoft/vscode-cpptools). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -286,6 +312,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the C++ extension. Please file the issue to the [C++ extension repository](https://github.com/microsoft/vscode-cpptools). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -299,6 +326,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the TypeScript language service. Please file the issue to the [TypeScript repository](https://github.com/microsoft/TypeScript/). Make sure to check their [contributing guidelines](https://github.com/microsoft/TypeScript/blob/master/CONTRIBUTING.md) and provide relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -312,6 +340,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the TypeScript/JavaScript language service. Please file the issue to the [TypeScript repository](https://github.com/microsoft/TypeScript/). Make sure to check their [contributing guidelines](https://github.com/microsoft/TypeScript/blob/master/CONTRIBUTING.md) and provide relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -325,6 +354,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the C# extension. Please file the issue to the [C# extension repository](https://github.com/OmniSharp/omnisharp-vscode.git). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -351,6 +381,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the PowerShell extension. Please file the issue to the [PowerShell extension repository](https://github.com/PowerShell/vscode-powershell). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -364,6 +395,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the LiveShare extension. Please file the issue to the [LiveShare repository](https://github.com/MicrosoftDocs/live-share). Make sure to check their [contributing guidelines](https://github.com/MicrosoftDocs/live-share/blob/master/CONTRIBUTING.md) and provide relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -377,6 +409,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the Docker extension. Please file the issue to the [Docker extension repository](https://github.com/microsoft/vscode-docker). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -390,6 +423,7 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the Java extension. Please file the issue to the [Java extension repository](https://github.com/redhat-developer/vscode-java). Make sure to check their [troubleshooting instructions](https://github.com/redhat-developer/vscode-java/wiki/Troubleshooting) and provide relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, @@ -403,9 +437,24 @@ "IllusionMH" ], "action": "close", + "reason": "not_planned", "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the Java Debugger extension. Please file the issue to the [Java Debugger repository](https://github.com/microsoft/vscode-java-debug). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, + { + "type": "comment", + "name": "extCodespaces", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "reason": "not_planned", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the Codespaces extension. Please file the issue in the [Codespaces Discussion Forum](http://aka.ms/ghcs-feedback). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" + }, { "type": "comment", "name": "gifPlease", @@ -416,7 +465,7 @@ "IllusionMH" ], "action": "comment", - "addLabel": "needs more info", + "addLabel": "info-needed", "comment": "Thanks for reporting this issue! Unfortunately, it's hard for us to understand what issue you're seeing. Please help us out by providing a screen recording showing exactly what isn't working as expected. While we can work with most standard formats, `.gif` files are preferred as they are displayed inline on GitHub. You may find https://gifcap.dev helpful as a browser-based gif recording tool.\n\nIf the issue depends on keyboard input, you can help us by enabling screencast mode for the recording (`Developer: Toggle Screencast Mode` in the command palette).\n\nHappy coding!" }, { @@ -439,6 +488,15 @@ "type": "label", "name": "*workspace-trust-docs", "action": "close", + "reason": "not_planned", "comment": "This issue appears to be the result of the new workspace trust feature shipped in June 2021. This security-focused feature has major impact on the functionality of VS Code. Due to the volume of issues, we ask that you take some time to review our [comprehensive documentation](https://aka.ms/vscode-workspace-trust) on the feature. If your issue is still not resolved, please let us know." + }, + { + "type": "label", + "name": "~verification-steps-needed", + "action": "updateLabels", + "addLabel": "verification-steps-needed", + "removeLabel": "~verification-steps-needed", + "comment": "Friendly ping! Looks like this issue requires some further steps to be verified. Please provide us with the steps necessary to verify this issue." } ] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 19314029215..5335e645320 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,5 +5,3 @@ * Ensure that the code is up-to-date with the `main` branch. * Include a description of the proposed changes and how to test them. --> - -This PR fixes # diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 97daf8fd946..8a0a39315bb 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -39,8 +39,7 @@ jobs: uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules22- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} @@ -92,8 +91,7 @@ jobs: uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules22- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} @@ -155,8 +153,7 @@ jobs: uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules22- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 088723285cf..d505e2b9129 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,8 +125,7 @@ jobs: uses: actions/cache@v2 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules22- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} @@ -197,8 +196,7 @@ jobs: uses: actions/cache@v2 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules22- + key: ${{ runner.os }}-cacheNodeModulesMacOS-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} @@ -271,8 +269,7 @@ jobs: uses: actions/cache@v2 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules22- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6c5d2999898..f64aa7df15c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,14 +24,14 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: javascript # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -45,4 +45,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/deep-classifier-runner.yml b/.github/workflows/deep-classifier-runner.yml index bae2eeb1967..a966318ddef 100644 --- a/.github/workflows/deep-classifier-runner.yml +++ b/.github/workflows/deep-classifier-runner.yml @@ -46,7 +46,7 @@ jobs: uses: ./actions/classifier-deep/apply/apply-labels with: configPath: classifier - allowLabels: "needs more info|new release|error-telemetry|*english-please|translation-required" + allowLabels: "info-needed|new release|error-telemetry|*english-please|translation-required" appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} manifestDbConnectionString: ${{secrets.MANIFEST_DB_CONNECTION_STRING}} token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} diff --git a/.github/workflows/english-please.yml b/.github/workflows/english-please.yml index da8ca03ddd8..2f24b039125 100644 --- a/.github/workflows/english-please.yml +++ b/.github/workflows/english-please.yml @@ -24,6 +24,6 @@ jobs: token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "needs more info" + needsMoreInfoLabel: "info-needed" translatorRequestedLabelPrefix: "translation-required-" translatorRequestedLabelColor: "c29cff" diff --git a/.github/workflows/needs-more-info-closer.yml b/.github/workflows/needs-more-info-closer.yml index 5e1f5b5c548..65805be0d51 100644 --- a/.github/workflows/needs-more-info-closer.yml +++ b/.github/workflows/needs-more-info-closer.yml @@ -1,4 +1,4 @@ -name: Needs More Info Closer +name: info-needed Closer on: schedule: - cron: 20 11 * * * # 4:20am Redmond @@ -17,12 +17,12 @@ jobs: ref: stable - name: Install Actions run: npm install --production --prefix ./actions - - name: Run Needs More Info Closer + - name: Run info-needed Closer uses: ./actions/needs-more-info-closer with: appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - label: needs more info + label: info-needed closeDays: 7 additionalTeam: "cleidigh|usernamehw|gjsjohnmurray|IllusionMH" closeComment: "This issue has been closed automatically because it needs more information and has not had recent activity. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" diff --git a/.github/workflows/on-label.yml b/.github/workflows/on-label.yml index 25f7a67c7a1..9771860d437 100644 --- a/.github/workflows/on-label.yml +++ b/.github/workflows/on-label.yml @@ -71,7 +71,8 @@ jobs: if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item') uses: ./actions/test-plan-item-validator with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} + token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} + refLabel: on-testplan label: testplan-item invalidLabel: invalid-testplan-item comment: Invalid test plan item. See errors below and the [test plan item spec](https://github.com/microsoft/vscode/wiki/Writing-Test-Plan-Items) for more information. This comment will go away when the issues are resolved. @@ -85,6 +86,6 @@ jobs: token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "needs more info" + needsMoreInfoLabel: "info-needed" translatorRequestedLabelPrefix: "translation-required-" translatorRequestedLabelColor: "c29cff" diff --git a/.github/workflows/on-open.yml b/.github/workflows/on-open.yml index af70c86caa0..8fef95d9e83 100644 --- a/.github/workflows/on-open.yml +++ b/.github/workflows/on-open.yml @@ -59,6 +59,16 @@ jobs: appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "needs more info" + needsMoreInfoLabel: "info-needed" translatorRequestedLabelPrefix: "translation-required-" translatorRequestedLabelColor: "c29cff" + # source of truth in ./test-plan-item-validator.yml + - name: Run Test Plan Item Validator + uses: ./actions/test-plan-item-validator + with: + token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} + refLabel: on-testplan + label: testplan-item + invalidLabel: invalid-testplan-item + comment: Invalid test plan item. See errors below and the [test plan item spec](https://github.com/microsoft/vscode/wiki/Writing-Test-Plan-Items) for more information. This comment will go away when the issues are resolved. + diff --git a/.github/workflows/test-plan-item-validator.yml b/.github/workflows/test-plan-item-validator.yml index 82bd093e039..d3b9284f9ae 100644 --- a/.github/workflows/test-plan-item-validator.yml +++ b/.github/workflows/test-plan-item-validator.yml @@ -3,7 +3,7 @@ on: issues: types: [edited] -# also edit in ./on-label.yml +# also edit in ./on-label.yml and ./on-open.yml jobs: main: runs-on: ubuntu-latest @@ -22,7 +22,8 @@ jobs: if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item') uses: ./actions/test-plan-item-validator with: + token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} + refLabel: on-testplan label: testplan-item - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} invalidLabel: invalid-testplan-item comment: Invalid test plan item. See errors below and the [test plan item spec](https://github.com/microsoft/vscode/wiki/Writing-Test-Plan-Items) for more information. This comment will go away when the issues are resolved. diff --git a/.mailmap b/.mailmap index d4542abf73c..4834393cff7 100644 --- a/.mailmap +++ b/.mailmap @@ -1,6 +1,4 @@ -Eric Amodio Eric Amodio -Eric Amodio Eric Amodio Daniel Imms Daniel Imms -Tanha Kabir Tanha Kabir Raymond Zhao Tyler Leonhardt Tyler Leonhardt +João Moreno João Moreno diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000000..0cf077e6b4c --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +16.14 diff --git a/.vscode/launch.json b/.vscode/launch.json index 27f23ed128b..b685af9c9be 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -24,7 +24,7 @@ ] }, { - "type": "pwa-chrome", + "type": "chrome", "request": "attach", "name": "Attach to Shared Process", "timeout": 30000, @@ -67,6 +67,7 @@ "name": "Attach to Main Process", "timeout": 30000, "port": 5875, + "continueOnAttach": true, "outFiles": [ "${workspaceFolder}/out/**/*.js" ], @@ -202,7 +203,7 @@ } }, { - "type": "pwa-chrome", + "type": "chrome", "request": "attach", "name": "Attach to VS Code", "browserAttachLocation": "workspace", @@ -216,7 +217,7 @@ "perScriptSourcemaps": "yes" }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Launch VS Code Internal", "windows": { @@ -237,7 +238,7 @@ "cleanUp": "wholeBrowser", "urlFilter": "*workbench.html*", "runtimeArgs": [ - "--inspect=5875", + "--inspect-brk=5875", "--no-cached-data", "--crash-reporter-directory=${workspaceFolder}/.profile-oss/crashes", // for general runtime freezes: https://github.com/microsoft/vscode/issues/127861#issuecomment-904144910 @@ -258,7 +259,7 @@ } }, { - "type": "pwa-node", + "type": "node", "request": "launch", "name": "VS Code Server (Web)", "runtimeExecutable": "${workspaceFolder}/scripts/code-server.sh", @@ -274,7 +275,7 @@ } }, { - "type": "pwa-node", + "type": "node", "request": "launch", "name": "Main Process", "attachSimplePort": 5875, @@ -295,7 +296,7 @@ } }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "outFiles": [], "perScriptSourcemaps": "yes", @@ -308,7 +309,7 @@ } }, { - "type": "pwa-msedge", + "type": "msedge", "request": "launch", "outFiles": [], "perScriptSourcemaps": "yes", @@ -403,7 +404,7 @@ } }, { - "type": "pwa-node", + "type": "node", "request": "launch", "name": "Run Unit Tests", "program": "${workspaceFolder}/test/unit/electron/index.js", @@ -433,7 +434,7 @@ } }, { - "type": "pwa-node", + "type": "node", "request": "launch", "name": "Run Unit Tests For Current File", "program": "${workspaceFolder}/test/unit/electron/index.js", @@ -468,10 +469,9 @@ "type": "node", "request": "launch", "name": "Launch Smoke Test", - "program": "${workspaceFolder}/test/smoke/out/main.js", + "program": "${workspaceFolder}/test/smoke/test/index.js", "cwd": "${workspaceFolder}/test/smoke", "timeout": 240000, - "port": 9999, "args": [ "-l", "${workspaceFolder}/.build/electron/Code - OSS.app/Contents/MacOS/Electron" @@ -512,9 +512,10 @@ } }, { - "name": "Search and Renderer processes", + "name": "Search, Renderer, and Main processes", "configurations": [ "Launch VS Code Internal", + "Attach to Main Process", "Attach to Search Process" ], "presentation": { @@ -523,9 +524,10 @@ } }, { - "name": "Renderer and Extension Host processes", + "name": "Renderer, Extension Host, and Main processes", "configurations": [ "Launch VS Code Internal", + "Attach to Main Process", "Attach to Extension Host" ], "presentation": { @@ -556,10 +558,11 @@ } }, { - "name": "Launch VS Code", + "name": "Renderer and Main processes", "stopAll": true, "configurations": [ "Launch VS Code Internal", + "Attach to Main Process" ], "preLaunchTask": "Ensure Prelaunch Dependencies" }, diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues index 3120d4ad8fc..fd582d87cf1 100644 --- a/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"June 2022\"" + "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"September 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index e1a91c7b80a..0eac8b51a1b 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-unpkg\n\n$MILESTONE=milestone:\"June 2022\"" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-unpkg\n\n$MILESTONE=milestone:\"August 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/inbox.github-issues b/.vscode/notebooks/inbox.github-issues index ad451a6f91a..10d7fd63e54 100644 --- a/.vscode/notebooks/inbox.github-issues +++ b/.vscode/notebooks/inbox.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$inbox -label:\"needs more info\" sort:created-desc" + "value": "$inbox -label:\"info-needed\" sort:created-desc" }, { "kind": 2, diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 342cb52b014..2032edb424b 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal\n\n$MILESTONE=milestone:\"June 2022\"\n\n$MINE=assignee:@me" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal\r\n\r\n$MILESTONE=milestone:\"August 2022\"\r\n\r\n$MINE=assignee:@me" }, { "kind": 1, @@ -147,7 +147,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed author:@me sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:needs-triage -label:verification-found" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed author:@me sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:triage-needed -label:verification-found" }, { "kind": 1, @@ -157,7 +157,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:bamurtaugh -author:bpasero -author:chrisdias -author:chrmarti -author:Chuxel -author:claudiaregio -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:DonJayamanne -author:dynamicwebpaige -author:eamodio -author:egamma -author:fiveisprime -author:greazer -author:gregvanl -author:hediet -author:IanMatthewHuff -author:isidorn -author:ItalyPaleAle -author:JacksonKearl -author:joaomoreno -author:joyceerhl -author:jrieken -author:karrtikr-author:kieferrm -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:ornellaalt -author:orta -author:rchiodo -author:rebornix -author:roblourens -author:rzhao271 -author:sana-ajani -author:sandy081 -author:sbatten -author:stevencl -author:tanhakabir -author:TylerLeonhardt -author:Tyriar -author:weinand -author:kimadeline -author:amunger" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:andreamah -author:bamurtaugh -author:bpasero -author:chrisdias -author:chrmarti -author:Chuxel -author:claudiaregio -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:DonJayamanne -author:egamma -author:fiveisprime -author:gregvanl -author:hediet -author:IanMatthewHuff -author:isidorn -author:joaomoreno -author:joyceerhl -author:jrieken -author:karrtikr -author:kieferrm -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:roblourens -author:rzhao271 -author:sandy081 -author:sbatten -author:stevencl -author:tanhakabir -author:TylerLeonhardt -author:Tyriar -author:weinand -author:amunger" }, { "kind": 1, diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index f596c6e2e1c..4562f07797d 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"June 2022\"" + "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"September 2022\"" }, { "kind": 1, @@ -92,7 +92,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream -label:polish -label:testplan-item -label:error-telemetry" + "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"info-needed\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream -label:polish -label:testplan-item -label:error-telemetry" }, { "kind": 1, @@ -102,7 +102,7 @@ { "kind": 2, "language": "github-issues", - "value": "repo:microsoft/vscode assignee:@me is:open type:issue -label:\"needs more info\" -label:api -label:api-finalization -label:api-proposal -label:authentication -label:bisect-ext -label:bracket-pair-colorization -label:bracket-pair-guides -label:breadcrumbs -label:callhierarchy -label:chrome-devtools -label:code-lens -label:color-palette -label:comments -label:config -label:context-keys -label:css-less-scss -label:custom-editors -label:debug -label:debug-disassembly -label:dialogs -label:diff-editor -label:dropdown -label:editor -label:editor-autoclosing -label:editor-autoindent -label:editor-bracket-matching -label:editor-clipboard -label:editor-code-actions -label:editor-color-picker -label:editor-columnselect -label:editor-commands -label:editor-comments -label:editor-contrib -label:editor-core -label:editor-drag-and-drop -label:editor-error-widget -label:editor-find -label:editor-folding -label:editor-highlight -label:editor-hover -label:editor-indent-detection -label:editor-indent-guides -label:editor-input -label:editor-input-IME -label:editor-insets -label:editor-minimap -label:editor-multicursor -label:editor-parameter-hints -label:editor-render-whitespace -label:editor-rendering -label:editor-RTL -label:editor-scrollbar -label:editor-symbols -label:editor-synced-region -label:editor-textbuffer -label:editor-theming -label:editor-wordnav -label:editor-wrapping -label:emmet -label:engineering -label:error-list -label:extension-host -label:extension-recommendations -label:extensions -label:extensions-development -label:file-decorations -label:file-encoding -label:file-explorer -label:file-glob -label:file-io -label:file-watcher -label:font-rendering -label:formatting -label:getting-started -label:ghost-text -label:git -label:github -label:gpu -label:grammar -label:grid-view -label:html -label:i18n -label:icon-brand -label:icons-product -label:image-preview -label:inlay-hints -label:inline-completions -label:install-update -label:intellisense-config -label:interactive-window -label:ipc -label:issue-bot -label:issue-reporter -label:javascript -label:json -label:keybindings -label:keybindings-editor -label:keyboard-layout -label:L10N -label:label-provider -label:languages-basic -label:languages-diagnostics -label:languages-guessing -label:layout -label:lcd-text-rendering -label:list -label:live-server -label:log -label:markdown -label:marketplace -label:menus -label:merge-conflict -label:network -label:notebook -label:notebook-api -label:notebook-celltoolbar -label:notebook-diff -label:notebook-dnd -label:notebook-folding -label:notebook-globaltoolbar -label:notebook-ipynb -label:notebook-kernel -label:notebook-keybinding -label:notebook-layout -label:notebook-markdown -label:notebook-minimap -label:notebook-multiselect -label:notebook-output -label:notebook-perf -label:notebook-statusbar -label:open-editors -label:opener -label:outline -label:output -label:perf -label:perf-bloat -label:perf-startup -label:php -label:portable-mode -label:proxy -label:quick-open -label:quick-pick -label:references-viewlet -label:release-notes -label:remote -label:remote-connection -label:remote-explorer -label:remotehub -label:rename -label:sandbox -label:sash -label:scm -label:screencast-mode -label:search -label:search-api -label:search-editor -label:search-replace -label:semantic-tokens -label:settings-editor -label:settings-sync -label:settings-sync-server -label:shared-process -label:simple-file-dialog -label:smart-select -label:snap -label:snippets -label:splitview -label:suggest -label:sync-error-handling -label:table -label:tasks -label:telemetry -label:terminal -label:terminal-conpty -label:terminal-editors -label:terminal-external -label:terminal-links -label:terminal-local-echo -label:terminal-profiles -label:terminal-reconnection -label:terminal-rendering -label:terminal-tabs -label:terminal-winpty -label:testing -label:themes -label:timeline -label:timeline-git -label:titlebar -label:tokenization -label:touch/pointer -label:trackpad/scroll -label:tree-views -label:tree-widget -label:typehierarchy -label:typescript -label:undo-redo -label:uri -label:ux -label:variable-resolving -label:VIM -label:virtual-workspaces -label:vscode-build -label:vscode-website -label:web -label:webview -label:webview-views -label:workbench-actions -label:workbench-cli -label:workbench-diagnostics -label:workbench-dnd -label:workbench-editor-grid -label:workbench-editor-groups -label:workbench-editor-resolver -label:workbench-editors -label:workbench-electron -label:workbench-feedback -label:workbench-history -label:workbench-hot-exit -label:workbench-hover -label:workbench-launch -label:workbench-link -label:workbench-multiroot -label:workbench-notifications -label:workbench-os-integration -label:workbench-rapid-render -label:workbench-run-as-admin -label:workbench-state -label:workbench-status -label:workbench-tabs -label:workbench-touchbar -label:workbench-untitled-editors -label:workbench-views -label:workbench-welcome -label:workbench-window -label:workbench-zen -label:workspace-edit -label:workspace-symbols -label:workspace-trust -label:zoom" + "value": "repo:microsoft/vscode assignee:@me is:open type:issue -label:\"info-needed\" -label:api -label:api-finalization -label:api-proposal -label:authentication -label:bisect-ext -label:bracket-pair-colorization -label:bracket-pair-guides -label:breadcrumbs -label:callhierarchy -label:chrome-devtools -label:code-lens -label:color-palette -label:comments -label:config -label:context-keys -label:css-less-scss -label:custom-editors -label:debug -label:debug-disassembly -label:dialogs -label:diff-editor -label:dropdown -label:editor -label:editor-autoclosing -label:editor-autoindent -label:editor-bracket-matching -label:editor-clipboard -label:editor-code-actions -label:editor-color-picker -label:editor-columnselect -label:editor-commands -label:editor-comments -label:editor-contrib -label:editor-core -label:editor-drag-and-drop -label:editor-error-widget -label:editor-find -label:editor-folding -label:editor-highlight -label:editor-hover -label:editor-indent-detection -label:editor-indent-guides -label:editor-input -label:editor-input-IME -label:editor-insets -label:editor-minimap -label:editor-multicursor -label:editor-parameter-hints -label:editor-render-whitespace -label:editor-rendering -label:editor-RTL -label:editor-scrollbar -label:editor-symbols -label:editor-synced-region -label:editor-textbuffer -label:editor-theming -label:editor-wordnav -label:editor-wrapping -label:emmet -label:engineering -label:error-list -label:extension-host -label:extension-recommendations -label:extensions -label:extensions-development -label:file-decorations -label:file-encoding -label:file-explorer -label:file-glob -label:file-io -label:file-watcher -label:font-rendering -label:formatting -label:getting-started -label:ghost-text -label:git -label:github -label:gpu -label:grammar -label:grid-view -label:html -label:i18n -label:icon-brand -label:icons-product -label:image-preview -label:inlay-hints -label:inline-completions -label:install-update -label:intellisense-config -label:interactive-window -label:ipc -label:issue-bot -label:issue-reporter -label:javascript -label:json -label:keybindings -label:keybindings-editor -label:keyboard-layout -label:L10N -label:label-provider -label:languages-basic -label:languages-diagnostics -label:languages-guessing -label:layout -label:lcd-text-rendering -label:list -label:live-server -label:log -label:markdown -label:marketplace -label:menus -label:merge-conflict -label:network -label:notebook -label:notebook-api -label:notebook-celltoolbar -label:notebook-diff -label:notebook-dnd -label:notebook-folding -label:notebook-globaltoolbar -label:notebook-ipynb -label:notebook-kernel -label:notebook-keybinding -label:notebook-layout -label:notebook-markdown -label:notebook-minimap -label:notebook-multiselect -label:notebook-output -label:notebook-perf -label:notebook-statusbar -label:open-editors -label:opener -label:outline -label:output -label:perf -label:perf-bloat -label:perf-startup -label:php -label:portable-mode -label:proxy -label:quick-open -label:quick-pick -label:references-viewlet -label:release-notes -label:remote -label:remote-connection -label:remote-explorer -label:remotehub -label:rename -label:sandbox -label:sash -label:scm -label:screencast-mode -label:search -label:search-api -label:search-editor -label:search-replace -label:semantic-tokens -label:settings-editor -label:settings-sync -label:settings-sync-server -label:shared-process -label:simple-file-dialog -label:smart-select -label:snap -label:snippets -label:splitview -label:suggest -label:sync-error-handling -label:table -label:tasks -label:telemetry -label:terminal -label:terminal-conpty -label:terminal-editors -label:terminal-external -label:terminal-links -label:terminal-local-echo -label:terminal-profiles -label:terminal-reconnection -label:terminal-rendering -label:terminal-tabs -label:terminal-winpty -label:testing -label:themes -label:timeline -label:timeline-git -label:titlebar -label:tokenization -label:touch/pointer -label:trackpad/scroll -label:tree-views -label:tree-widget -label:typehierarchy -label:typescript -label:undo-redo -label:uri -label:ux -label:variable-resolving -label:VIM -label:virtual-workspaces -label:vscode-build -label:vscode-website -label:web -label:webview -label:webview-views -label:workbench-actions -label:workbench-cli -label:workbench-diagnostics -label:workbench-dnd -label:workbench-editor-grid -label:workbench-editor-groups -label:workbench-editor-resolver -label:workbench-editors -label:workbench-electron -label:workbench-feedback -label:workbench-history -label:workbench-hot-exit -label:workbench-hover -label:workbench-launch -label:workbench-link -label:workbench-multiroot -label:workbench-notifications -label:workbench-os-integration -label:workbench-rapid-render -label:workbench-run-as-admin -label:workbench-state -label:workbench-status -label:workbench-tabs -label:workbench-touchbar -label:workbench-untitled-editors -label:workbench-views -label:workbench-welcome -label:workbench-window -label:workbench-zen -label:workspace-edit -label:workspace-symbols -label:workspace-trust -label:zoom" }, { "kind": 1, @@ -112,7 +112,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:\"needs more info\"" + "value": "$repos assignee:@me is:open label:\"info-needed\"" }, { "kind": 1, diff --git a/.vscode/settings.json b/.vscode/settings.json index 71bded80a79..0529bf5aba5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -41,11 +41,6 @@ } } ], - "eslint.options": { - "rulePaths": [ - "./build/lib/eslint" - ] - }, "typescript.tsdk": "node_modules/typescript/lib", "npm.exclude": "**/extensions/**", "npm.packageManager": "yarn", diff --git a/.yarnrc b/.yarnrc index 507a7bbdfff..afa220d0f75 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,4 +1,4 @@ disturl "https://electronjs.org/headers" -target "18.3.5" +target "19.0.12" runtime "electron" build_from_source "true" diff --git a/README.md b/README.md index ba8f7224ff7..eb76f98421e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ please see the document [How to Contribute](https://github.com/microsoft/vscode/ * [Request a new feature](CONTRIBUTING.md) * Upvote [popular feature requests](https://github.com/microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) * [File an issue](https://github.com/microsoft/vscode/issues) +* Connect with the extension author community on [GitHub Discussions](https://github.com/microsoft/vscode-discussions/discussions) or [Slack](https://aka.ms/vscode-dev-community) * Follow [@code](https://twitter.com/code) and let us know what you think! See our [wiki](https://github.com/microsoft/vscode/wiki/Feedback-Channels) for a description of each of these channels and information on some other available community-driven channels. diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 9c691ad41e3..5c36a652b4b 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -31,7 +31,7 @@ This project incorporates components from the projects listed below. The origina 24. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) 25. James-Yu/LaTeX-Workshop version 8.19.1 (https://github.com/James-Yu/LaTeX-Workshop) 26. jeff-hykin/better-c-syntax version 1.13.2 (https://github.com/jeff-hykin/better-c-syntax) -27. jeff-hykin/better-cpp-syntax version 1.15.17 (https://github.com/jeff-hykin/better-cpp-syntax) +27. jeff-hykin/better-cpp-syntax version 1.15.18 (https://github.com/jeff-hykin/better-cpp-syntax) 28. jeff-hykin/better-objc-syntax version 0.2.0 (https://github.com/jeff-hykin/better-objc-syntax) 29. jeff-hykin/better-objcpp-syntax version 0.1.0 (https://github.com/jeff-hykin/better-objcpp-syntax) 30. jlelong/vscode-latex-basics version 1.3.0 (https://github.com/jlelong/vscode-latex-basics) @@ -47,7 +47,7 @@ This project incorporates components from the projects listed below. The origina 40. microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/microsoft/TypeScript-TmLanguage) 41. microsoft/vscode-JSON.tmLanguage (https://github.com/microsoft/vscode-JSON.tmLanguage) 42. microsoft/vscode-markdown-tm-grammar version 1.0.0 (https://github.com/microsoft/vscode-markdown-tm-grammar) -43. microsoft/vscode-mssql version 1.10.1 (https://github.com/microsoft/vscode-mssql) +43. microsoft/vscode-mssql version 1.16.0 (https://github.com/microsoft/vscode-mssql) 44. mmims/language-batchfile version 0.7.6 (https://github.com/mmims/language-batchfile) 45. NVIDIA/cuda-cpp-grammar (https://github.com/NVIDIA/cuda-cpp-grammar) 46. PowerShell/EditorSyntax version 1.0.0 (https://github.com/PowerShell/EditorSyntax) @@ -73,7 +73,7 @@ This project incorporates components from the projects listed below. The origina 66. TypeScript-TmLanguage version 1.0.0 (https://github.com/microsoft/TypeScript-TmLanguage) 67. Unicode version 12.0.0 (https://home.unicode.org/) 68. vscode-codicons version 0.0.14 (https://github.com/microsoft/vscode-codicons) -69. vscode-logfile-highlighter version 2.11.0 (https://github.com/emilast/vscode-logfile-highlighter) +69. vscode-logfile-highlighter version 2.15.0 (https://github.com/emilast/vscode-logfile-highlighter) 70. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) 71. vscode-win32-app-container-tokens (https://github.com/microsoft/vscode-win32-app-container-tokens) 72. Web Background Synchronization (https://github.com/WICG/background-sync) diff --git a/build/.cachesalt b/build/.cachesalt index 11b63081f5a..4f9c24c0470 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -2022-06-10T10:20:54.664Z +2022-08-01T11:24:47.411Z diff --git a/build/.webignore b/build/.webignore index 563dfb0000c..1a5b3ee2c10 100644 --- a/build/.webignore +++ b/build/.webignore @@ -20,6 +20,9 @@ vscode-textmate/webpack.config.js xterm/src/** +xterm-addon-canvas/src/** +xterm-addon-canvas/out/** + xterm-addon-search/src/** xterm-addon-search/out/** xterm-addon-search/fixtures/** diff --git a/build/azure-pipelines/common/computeBuiltInDepsCacheKey.js b/build/azure-pipelines/common/computeBuiltInDepsCacheKey.js new file mode 100644 index 00000000000..abc90f6ed2c --- /dev/null +++ b/build/azure-pipelines/common/computeBuiltInDepsCacheKey.js @@ -0,0 +1,15 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = require("fs"); +const path = require("path"); +const crypto = require("crypto"); +const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../product.json'), 'utf8')); +const shasum = crypto.createHash('sha1'); +for (const ext of productjson.builtInExtensions) { + shasum.update(`${ext.name}@${ext.version}`); +} +process.stdout.write(shasum.digest('hex')); diff --git a/build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts b/build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts new file mode 100644 index 00000000000..f0554361607 --- /dev/null +++ b/build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as crypto from 'crypto'; + +const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../product.json'), 'utf8')); +const shasum = crypto.createHash('sha1'); + +for (const ext of productjson.builtInExtensions) { + shasum.update(`${ext.name}@${ext.version}`); +} + +process.stdout.write(shasum.digest('hex')); diff --git a/build/azure-pipelines/darwin/product-build-darwin-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-sign.yml index 059e848c0b1..a4ac3731104 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-sign.yml @@ -38,6 +38,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -47,6 +48,12 @@ steps: cacheHitVar: NODE_MODULES_RESTORED displayName: Restore node_modules cache + - task: Cache@2 + inputs: + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions + - script: | set -e tar -xzf .build/node_modules_cache/cache.tgz @@ -88,6 +95,13 @@ steps: displayName: Install dependencies condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + - script: | + set -e + node build/lib/builtInExtensions.js + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + - script: | set -e node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt @@ -100,12 +114,6 @@ steps: artifact: unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive displayName: Download $(VSCODE_ARCH) artifact - - script: | - set -e - unzip $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive/VSCode-darwin-$(VSCODE_ARCH).zip -d $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) - mv $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive/VSCode-darwin-$(VSCODE_ARCH).zip $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip - displayName: Unzip & move - - task: UseDotNet@2 inputs: version: 2.x @@ -115,20 +123,38 @@ steps: - script: | set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(agent.builddirectory) VSCode-darwin-$(VSCODE_ARCH).zip + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive VSCode-darwin-$(VSCODE_ARCH).zip displayName: Codesign - script: | set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-notarize $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(agent.builddirectory) VSCode-darwin-$(VSCODE_ARCH).zip + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-notarize $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive VSCode-darwin-$(VSCODE_ARCH).zip displayName: Notarize - script: | set -e - APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + unzip $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive/VSCode-darwin-$(VSCODE_ARCH).zip -d $(Agent.BuildDirectory)/VSCode-darwin-$(VSCODE_ARCH) + displayName: Extract signed app + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) + + - script: | + set -e + APP_ROOT="$(Agent.BuildDirectory)/VSCode-darwin-$(VSCODE_ARCH)" APP_NAME="`ls $APP_ROOT | head -n 1`" - "$APP_ROOT/$APP_NAME/Contents/Resources/app/bin/code" --export-default-configuration=.build - displayName: Verify start after signing (export configuration) + echo "##vso[task.setvariable variable=APP_PATH]$APP_ROOT/$APP_NAME" + displayName: Find application path + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) + + - script: | + set -e + codesign -dv --deep --verbose=4 "$(APP_PATH)" + displayName: Verify signature + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) + + - script: | + set -e + "$(APP_PATH)/Contents/Resources/app/bin/code" --export-default-configuration=.build + displayName: Verify signed application starts OK condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - script: | @@ -141,9 +167,9 @@ steps: echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable - - script: mv $(agent.builddirectory)/VSCode-darwin-x64.zip $(agent.builddirectory)/VSCode-darwin.zip - displayName: Rename x64 build to it's legacy name + - script: mv $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive/VSCode-darwin-x64.zip $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive/VSCode-darwin.zip + displayName: Rename x64 build to its legacy name condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - - publish: $(Agent.BuildDirectory)/VSCode-$(ASSET_ID).zip + - publish: $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive/VSCode-$(ASSET_ID).zip artifact: vscode_client_darwin_$(VSCODE_ARCH)_archive diff --git a/build/azure-pipelines/darwin/product-build-darwin-test.yml b/build/azure-pipelines/darwin/product-build-darwin-test.yml index c5547cbdcf2..1094b41ca21 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-test.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-test.yml @@ -1,4 +1,6 @@ parameters: + - name: VSCODE_QUALITY + type: string - name: VSCODE_RUN_UNIT_TESTS type: boolean - name: VSCODE_RUN_INTEGRATION_TESTS @@ -14,25 +16,43 @@ steps: displayName: Download Electron and Playwright - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - - script: | - set -e - ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + ./scripts/test.sh --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 - - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - - script: | - set -e - yarn test-node --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 + - script: | + set -e + yarn test-node + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 - - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - - script: | - set -e - DEBUG=*browser* yarn test-browser-no-install --sequential --build --browser chromium --browser webkit --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser, Chromium & Webkit) - timeoutInMinutes: 30 + - script: | + set -e + DEBUG=*browser* yarn test-browser-no-install --sequential --browser chromium --browser webkit --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser, Chromium & Webkit) + timeoutInMinutes: 30 + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + ./scripts/test.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + + - script: | + set -e + yarn test-node --build + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + + - script: | + set -e + DEBUG=*browser* yarn test-browser-no-install --sequential --build --browser chromium --browser webkit --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser, Chromium & Webkit) + timeoutInMinutes: 30 - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - script: | @@ -46,6 +66,7 @@ steps: compile-extension:html-language-features-server \ compile-extension:ipynb \ compile-extension:json-language-features-server \ + compile-extension:markdown-language-features-server \ compile-extension:markdown-language-features \ compile-extension-media \ compile-extension:microsoft-authentication \ @@ -56,38 +77,42 @@ steps: compile-extension:vscode-test-resolver displayName: Build integration tests - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - script: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) - APP_NAME="`ls $APP_ROOT | head -n 1`" - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin-$(VSCODE_ARCH)" \ - ./scripts/test-integration.sh --build --tfs "Integration Tests" - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + ./scripts/test-integration.sh --tfs "Integration Tests" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - script: | - set -e - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin-$(VSCODE_ARCH)" \ - ./scripts/test-web-integration.sh --browser webkit - displayName: Run integration tests (Browser, Webkit) - timeoutInMinutes: 20 + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin-$(VSCODE_ARCH)" \ + ./scripts/test-integration.sh --build --tfs "Integration Tests" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - script: | - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) - APP_NAME="`ls $APP_ROOT | head -n 1`" - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin-$(VSCODE_ARCH)" \ - ./scripts/test-remote-integration.sh - displayName: Run integration tests (Remote) - timeoutInMinutes: 20 + - script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin-$(VSCODE_ARCH)" \ + ./scripts/test-web-integration.sh --browser webkit + displayName: Run integration tests (Browser, Webkit) + timeoutInMinutes: 20 + + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin-$(VSCODE_ARCH)" \ + ./scripts/test-remote-integration.sh + displayName: Run integration tests (Remote) + timeoutInMinutes: 20 - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - script: | @@ -97,35 +122,44 @@ steps: continueOnError: true condition: succeededOrFailed() - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - script: | - set -e - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin-$(VSCODE_ARCH)" \ - yarn smoketest-no-compile --web --tracing --headless - timeoutInMinutes: 20 - displayName: Run smoke tests (Browser, Chromium) + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + yarn --cwd test/smoke compile + displayName: Compile smoke tests - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - script: | - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) - APP_NAME="`ls $APP_ROOT | head -n 1`" - yarn smoketest-no-compile --tracing --build "$APP_ROOT/$APP_NAME" - timeoutInMinutes: 20 - displayName: Run smoke tests (Electron) + - script: | + set -e + yarn smoketest-no-compile --tracing + timeoutInMinutes: 20 + displayName: Run smoke tests (Electron) - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - script: | - set -e - yarn gulp compile-extension:vscode-test-resolver - APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) - APP_NAME="`ls $APP_ROOT | head -n 1`" - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin-$(VSCODE_ARCH)" \ - yarn smoketest-no-compile --tracing --remote --build "$APP_ROOT/$APP_NAME" - timeoutInMinutes: 20 - displayName: Run smoke tests (Remote) + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + yarn smoketest-no-compile --tracing --build "$APP_ROOT/$APP_NAME" + timeoutInMinutes: 20 + displayName: Run smoke tests (Electron) + + - script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin-$(VSCODE_ARCH)" \ + yarn smoketest-no-compile --web --tracing --headless + timeoutInMinutes: 20 + displayName: Run smoke tests (Browser, Chromium) + + - script: | + set -e + yarn gulp compile-extension:vscode-test-resolver + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin-$(VSCODE_ARCH)" \ + yarn smoketest-no-compile --tracing --remote --build "$APP_ROOT/$APP_NAME" + timeoutInMinutes: 20 + displayName: Run smoke tests (Remote) - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - script: | set -e ps -ef @@ -147,7 +181,6 @@ steps: continueOnError: true condition: failed() - - ${{ if or(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: # In order to properly symbolify above crash reports # (if any), we need the compiled native modules too - task: PublishPipelineArtifact@0 @@ -163,7 +196,6 @@ steps: continueOnError: true condition: failed() - - ${{ if or(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - task: PublishPipelineArtifact@0 inputs: targetPath: .build/logs diff --git a/build/azure-pipelines/darwin/product-build-darwin-universal.yml b/build/azure-pipelines/darwin/product-build-darwin-universal.yml index 929aaf42038..ebc7104d6ce 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-universal.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-universal.yml @@ -38,6 +38,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -47,6 +48,12 @@ steps: cacheHitVar: NODE_MODULES_RESTORED displayName: Restore node_modules cache + - task: Cache@2 + inputs: + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions + - script: | set -e tar -xzf .build/node_modules_cache/cache.tgz @@ -88,6 +95,13 @@ steps: displayName: Install dependencies condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + - script: | + set -e + node build/lib/builtInExtensions.js + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + - script: | set -e node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index e8a1c70160d..df4b8abfa70 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -11,6 +11,11 @@ parameters: type: boolean steps: + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 + - task: NodeTool@0 inputs: versionSpec: "16.x" @@ -23,16 +28,18 @@ steps: KeyVaultName: vscode SecretsFilter: "github-distro-mixin-password,macos-developer-certificate,macos-developer-certificate-key" - - task: DownloadPipelineArtifact@2 - inputs: - artifact: Compilation - path: $(Build.ArtifactStagingDirectory) - displayName: Download compilation output + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: Compilation + path: $(Build.ArtifactStagingDirectory) + displayName: Download compilation output - - script: | - set -e - tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz - displayName: Extract compilation output + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz + displayName: Extract compilation output - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - script: | @@ -65,6 +72,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -74,19 +82,18 @@ steps: cacheHitVar: NODE_MODULES_RESTORED displayName: Restore node_modules cache + - task: Cache@2 + inputs: + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions + - script: | set -e tar -xzf .build/node_modules_cache/cache.tgz condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true')) displayName: Extract node_modules cache - - script: | - set -e - npm install -g node-gyp@latest - node-gyp --version - displayName: Update node-gyp - condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) - - script: | set -e npx https://aka.ms/enablesecurefeed standAlone @@ -115,6 +122,13 @@ steps: displayName: Install dependencies condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + - script: | + set -e + node build/lib/builtInExtensions.js + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + - script: | set -e node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt @@ -130,11 +144,12 @@ steps: node build/azure-pipelines/mixin displayName: Mix in quality - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-darwin-$(VSCODE_ARCH)-min-ci - displayName: Build client + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-darwin-$(VSCODE_ARCH)-min-ci + displayName: Build client - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - script: | @@ -142,17 +157,26 @@ steps: node build/azure-pipelines/mixin --server displayName: Mix in server quality - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-darwin-$(VSCODE_ARCH)-min-ci - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-web-darwin-$(VSCODE_ARCH)-min-ci - displayName: Build Server + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-darwin-$(VSCODE_ARCH)-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-web-darwin-$(VSCODE_ARCH)-min-ci + displayName: Build Server + + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp "transpile-client-swc" "transpile-extensions" + displayName: Transpile - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - template: product-build-darwin-test.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} diff --git a/build/azure-pipelines/linux/product-build-alpine.yml b/build/azure-pipelines/linux/product-build-alpine.yml index 3aef7279243..c60f16d0804 100644 --- a/build/azure-pipelines/linux/product-build-alpine.yml +++ b/build/azure-pipelines/linux/product-build-alpine.yml @@ -58,6 +58,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js "alpine" $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -67,6 +68,12 @@ steps: cacheHitVar: NODE_MODULES_RESTORED displayName: Restore node_modules cache + - task: Cache@2 + inputs: + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions + - script: | set -e tar -xzf .build/node_modules_cache/cache.tgz @@ -98,6 +105,13 @@ steps: displayName: Install dependencies condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + - script: | + set -e + node build/lib/builtInExtensions.js + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + - script: | set -e node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt diff --git a/build/azure-pipelines/linux/product-build-linux-client-test.yml b/build/azure-pipelines/linux/product-build-linux-client-test.yml index ae1e77aaa73..31d477e93aa 100644 --- a/build/azure-pipelines/linux/product-build-linux-client-test.yml +++ b/build/azure-pipelines/linux/product-build-linux-client-test.yml @@ -1,4 +1,6 @@ parameters: + - name: VSCODE_QUALITY + type: string - name: VSCODE_RUN_UNIT_TESTS type: boolean - name: VSCODE_RUN_INTEGRATION_TESTS @@ -13,38 +15,68 @@ steps: yarn npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" displayName: Download Electron and Playwright - - script: | - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - ELECTRON_ROOT=.build/electron - sudo chown root $APP_ROOT/chrome-sandbox - sudo chown root $ELECTRON_ROOT/chrome-sandbox - sudo chmod 4755 $APP_ROOT/chrome-sandbox - sudo chmod 4755 $ELECTRON_ROOT/chrome-sandbox - stat $APP_ROOT/chrome-sandbox - stat $ELECTRON_ROOT/chrome-sandbox - displayName: Change setuid helper binary permission - - - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - script: | set -e - ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 + sudo apt-get update + sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 + 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 + displayName: Setup build environment - - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - script: | set -e - yarn test-node --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 + APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + ELECTRON_ROOT=.build/electron + sudo chown root $APP_ROOT/chrome-sandbox + sudo chown root $ELECTRON_ROOT/chrome-sandbox + sudo chmod 4755 $APP_ROOT/chrome-sandbox + sudo chmod 4755 $ELECTRON_ROOT/chrome-sandbox + stat $APP_ROOT/chrome-sandbox + stat $ELECTRON_ROOT/chrome-sandbox + displayName: Change setuid helper binary permission - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - - script: | - set -e - DEBUG=*browser* yarn test-browser-no-install --build --browser chromium --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 15 + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + + - script: | + set -e + yarn test-node + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + + - script: | + set -e + DEBUG=*browser* yarn test-browser-no-install --browser chromium --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 15 + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + ./scripts/test.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + + - script: | + set -e + yarn test-node --build + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + + - script: | + set -e + DEBUG=*browser* yarn test-browser-no-install --build --browser chromium --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 15 - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - script: | @@ -58,6 +90,7 @@ steps: compile-extension:html-language-features-server \ compile-extension:ipynb \ compile-extension:json-language-features-server \ + compile-extension:markdown-language-features-server \ compile-extension:markdown-language-features \ compile-extension-media \ compile-extension:microsoft-authentication \ @@ -69,39 +102,57 @@ steps: displayName: Build integration tests - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - script: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") - INTEGRATION_TEST_APP_NAME="$APP_NAME" \ - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ - ./scripts/test-integration.sh --build --tfs "Integration Tests" - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - script: | - set -e - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \ - ./scripts/test-web-integration.sh --browser chromium - displayName: Run integration tests (Browser, Chromium) - timeoutInMinutes: 20 + - script: | + set -e + ./scripts/test-web-integration.sh --browser chromium + displayName: Run integration tests (Browser, Chromium) + timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - script: | - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") - INTEGRATION_TEST_APP_NAME="$APP_NAME" \ - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ - ./scripts/test-remote-integration.sh - displayName: Run integration tests (Remote) - timeoutInMinutes: 20 + - script: | + set -e + ./scripts/test-remote-integration.sh + displayName: Run integration tests (Remote) + timeoutInMinutes: 20 + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") + INTEGRATION_TEST_APP_NAME="$APP_NAME" \ + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ + ./scripts/test-integration.sh --build --tfs "Integration Tests" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 + + - script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \ + ./scripts/test-web-integration.sh --browser chromium + displayName: Run integration tests (Browser, Chromium) + timeoutInMinutes: 20 + + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") + INTEGRATION_TEST_APP_NAME="$APP_NAME" \ + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ + ./scripts/test-remote-integration.sh + displayName: Run integration tests (Remote) + timeoutInMinutes: 20 - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - script: | @@ -113,33 +164,55 @@ steps: continueOnError: true condition: succeededOrFailed() - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - script: | - set -e - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \ - yarn smoketest-no-compile --web --tracing --headless --electronArgs="--disable-dev-shm-usage" - timeoutInMinutes: 20 - displayName: Run smoke tests (Browser, Chromium) + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + yarn --cwd test/smoke compile + displayName: Compile smoke tests - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - script: | - set -e - APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - yarn smoketest-no-compile --tracing --build "$APP_PATH" - timeoutInMinutes: 20 - displayName: Run smoke tests (Electron) + - script: | + set -e + yarn smoketest-no-compile --tracing + timeoutInMinutes: 20 + displayName: Run smoke tests (Electron) - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - script: | - set -e - yarn gulp compile-extension:vscode-test-resolver - APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ - yarn smoketest-no-compile --tracing --remote --build "$APP_PATH" - timeoutInMinutes: 20 - displayName: Run smoke tests (Remote) + - script: | + set -e + yarn smoketest-no-compile --web --tracing --headless --electronArgs="--disable-dev-shm-usage" + timeoutInMinutes: 20 + displayName: Run smoke tests (Browser, Chromium) + + - script: | + set -e + yarn gulp compile-extension:vscode-test-resolver + yarn smoketest-no-compile --remote --tracing + timeoutInMinutes: 20 + displayName: Run smoke tests (Remote) + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + yarn smoketest-no-compile --tracing --build "$APP_PATH" + timeoutInMinutes: 20 + displayName: Run smoke tests (Electron) + + - script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \ + yarn smoketest-no-compile --web --tracing --headless --electronArgs="--disable-dev-shm-usage" + timeoutInMinutes: 20 + displayName: Run smoke tests (Browser, Chromium) + + - script: | + set -e + yarn gulp compile-extension:vscode-test-resolver + APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ + yarn smoketest-no-compile --tracing --remote --build "$APP_PATH" + timeoutInMinutes: 20 + displayName: Run smoke tests (Remote) - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - script: | set -e ps -ef @@ -163,7 +236,6 @@ steps: continueOnError: true condition: failed() - - ${{ if or(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: # In order to properly symbolify above crash reports # (if any), we need the compiled native modules too - task: PublishPipelineArtifact@0 @@ -179,7 +251,6 @@ steps: continueOnError: true condition: failed() - - ${{ if or(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - task: PublishPipelineArtifact@0 inputs: targetPath: .build/logs diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index ed4d853230b..f966480819f 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -11,6 +11,11 @@ parameters: type: boolean steps: + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 + - task: NodeTool@0 inputs: versionSpec: "16.x" @@ -23,33 +28,37 @@ steps: KeyVaultName: vscode SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" - - task: DownloadPipelineArtifact@2 - inputs: - artifact: Compilation - path: $(Build.ArtifactStagingDirectory) - displayName: Download compilation output + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: Compilation + path: $(Build.ArtifactStagingDirectory) + displayName: Download compilation output - - task: DownloadPipelineArtifact@2 - inputs: - artifact: reh_node_modules-$(VSCODE_ARCH) - path: $(Build.ArtifactStagingDirectory) - displayName: Download server build dependencies - condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'armhf')) + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: reh_node_modules-$(VSCODE_ARCH) + path: $(Build.ArtifactStagingDirectory) + displayName: Download server build dependencies + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'armhf')) - - script: | - set -e - # Start X server - /etc/init.d/xvfb start - # Start dbus session - DBUS_LAUNCH_RESULT=$(sudo dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address) - echo "##vso[task.setvariable variable=DBUS_SESSION_BUS_ADDRESS]$DBUS_LAUNCH_RESULT" - displayName: Setup system services - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + # Start X server + /etc/init.d/xvfb start + # Start dbus session + DBUS_LAUNCH_RESULT=$(sudo dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address) + echo "##vso[task.setvariable variable=DBUS_SESSION_BUS_ADDRESS]$DBUS_LAUNCH_RESULT" + displayName: Setup system services + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - - script: | - set -e - tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz - displayName: Extract compilation output + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz + displayName: Extract compilation output - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - script: | @@ -82,14 +91,30 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - task: Cache@2 + inputs: + key: "genericNodeModules | $(Agent.OS) | .build/yarnlockhash" + path: .build/node_modules_cache + cacheHitVar: NODE_MODULES_RESTORED + displayName: Restore node_modules cache + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: Cache@2 + inputs: + key: "nodeModules | $(Agent.OS) | .build/yarnlockhash" + path: .build/node_modules_cache + cacheHitVar: NODE_MODULES_RESTORED + displayName: Restore node_modules cache + - task: Cache@2 inputs: - key: "nodeModules | $(Agent.OS) | .build/yarnlockhash" - path: .build/node_modules_cache - cacheHitVar: NODE_MODULES_RESTORED - displayName: Restore node_modules cache + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions - script: | set -e @@ -171,10 +196,18 @@ steps: - script: | set -e - rm -rf remote/node_modules - tar -xzf $(Build.ArtifactStagingDirectory)/reh_node_modules-$(VSCODE_ARCH).tar.gz --directory $(Build.SourcesDirectory)/remote - displayName: Extract server node_modules output - condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'armhf')) + node build/lib/builtInExtensions.js + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + rm -rf remote/node_modules + tar -xzf $(Build.ArtifactStagingDirectory)/reh_node_modules-$(VSCODE_ARCH).tar.gz --directory $(Build.SourcesDirectory)/remote + displayName: Extract server node_modules output + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'armhf')) - script: | set -e @@ -190,11 +223,12 @@ steps: node build/azure-pipelines/mixin displayName: Mix in quality - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-linux-$(VSCODE_ARCH)-min-ci - displayName: Build + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-linux-$(VSCODE_ARCH)-min-ci + displayName: Build - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - script: | @@ -202,17 +236,26 @@ steps: node build/azure-pipelines/mixin --server displayName: Mix in server quality - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-linux-$(VSCODE_ARCH)-min-ci - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-web-linux-$(VSCODE_ARCH)-min-ci - displayName: Build Server + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-linux-$(VSCODE_ARCH)-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-web-linux-$(VSCODE_ARCH)-min-ci + displayName: Build Server + + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp "transpile-client-swc" "transpile-extensions" + displayName: Transpile - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - template: product-build-linux-client-test.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} diff --git a/build/azure-pipelines/product-build-pr-cache.yml b/build/azure-pipelines/product-build-pr-cache.yml new file mode 100644 index 00000000000..042325394d3 --- /dev/null +++ b/build/azure-pipelines/product-build-pr-cache.yml @@ -0,0 +1,73 @@ +steps: + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 + + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - script: | + mkdir -p .build + node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash + displayName: Prepare yarn cache flags + + - task: Cache@2 + inputs: + key: "genericNodeModules | $(Agent.OS) | .build/yarnlockhash" + path: .build/node_modules_cache + cacheHitVar: NODE_MODULES_RESTORED + displayName: Restore node_modules cache + + - task: Cache@2 + inputs: + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions + + - script: | + set -e + tar -xzf .build/node_modules_cache/cache.tgz + condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true')) + displayName: Extract node_modules cache + + - script: | + set -e + npx https://aka.ms/enablesecurefeed standAlone + timeoutInMinutes: 5 + retryCountOnTaskFailure: 3 + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) + displayName: Switch to Terrapin packages + + - script: | + set -e + for i in {1..3}; do # try 3 times, for Terrapin + yarn --frozen-lockfile --check-files && break + if [ $i -eq 3 ]; then + echo "Yarn failed too many times" >&2 + exit 1 + fi + echo "Yarn failed $i, trying again..." + done + env: + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Install dependencies + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + + - script: | + set -e + node build/lib/builtInExtensions.js + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + + - script: | + set -e + node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt + mkdir -p .build/node_modules_cache + tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + displayName: Create node_modules archive diff --git a/build/azure-pipelines/product-build-pr.yml b/build/azure-pipelines/product-build-pr.yml index c8e23162f07..8362da25ee5 100644 --- a/build/azure-pipelines/product-build-pr.yml +++ b/build/azure-pipelines/product-build-pr.yml @@ -6,15 +6,6 @@ pr: branches: include: ["main", "release/*"] -resources: - containers: - - container: centos7-devtoolset8-x64 - image: vscodehub.azurecr.io/vscode-linux-build-agent:centos7-devtoolset8-x64 - options: --user 0:0 --cap-add SYS_ADMIN - - container: vscode-bionic-x64 - image: vscodehub.azurecr.io/vscode-linux-build-agent:bionic-x64 - options: --user 0:0 --cap-add SYS_ADMIN - variables: - name: Codeql.SkipTaskAutoInjection value: true @@ -22,6 +13,8 @@ variables: value: true - name: ENABLE_TERRAPIN value: false + - name: VSCODE_CIBUILD + value: ${{ in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') }} - name: VSCODE_PUBLISH value: false - name: VSCODE_QUALITY @@ -29,173 +22,168 @@ variables: - name: VSCODE_STEP_ON_IT value: false -stages: - - stage: Compile - jobs: - - job: Compile - pool: vscode-1es-vscode-linux-18.04 - variables: - VSCODE_ARCH: x64 - steps: - - template: product-compile.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} +jobs: + - ${{ if ne(variables['VSCODE_CIBUILD'], true) }}: + - job: Compile + displayName: Compile & Hygiene + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + steps: + - template: product-compile.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - - stage: LinuxServerDependencies - dependsOn: [] - pool: vscode-1es-vscode-linux-18.04 - jobs: - - job: x64 - container: centos7-devtoolset8-x64 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - steps: - - template: linux/product-build-linux-server.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + - job: Linuxx64UnitTest + displayName: Linux (Unit Tests) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: true + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false - - stage: Windows - dependsOn: - - Compile - pool: vscode-1es-vscode-windows-2019 - jobs: - - job: WindowsUnitTests - displayName: Unit Tests - timeoutInMinutes: 120 - variables: - VSCODE_ARCH: x64 - steps: - - template: win32/product-build-win32.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: true - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: false - - job: WindowsIntegrationTests - displayName: Integration Tests - timeoutInMinutes: 120 - variables: - VSCODE_ARCH: x64 - steps: - - template: win32/product-build-win32.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: true - VSCODE_RUN_SMOKE_TESTS: false - - job: WindowsSmokeTests - displayName: Smoke Tests - timeoutInMinutes: 120 - variables: - VSCODE_ARCH: x64 - steps: - - template: win32/product-build-win32.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: true + - job: Linuxx64IntegrationTest + displayName: Linux (Integration Tests) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: true + VSCODE_RUN_SMOKE_TESTS: false - - stage: Linux - dependsOn: - - Compile - - LinuxServerDependencies - pool: vscode-1es-vscode-linux-18.04 - jobs: - - job: Linuxx64UnitTest - displayName: Unit Tests - container: vscode-bionic-x64 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: true - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: false - - job: Linuxx64IntegrationTest - displayName: Integration Tests - container: vscode-bionic-x64 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: true - VSCODE_RUN_SMOKE_TESTS: false - - job: Linuxx64SmokeTest - displayName: Smoke Tests - container: vscode-bionic-x64 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: true + - job: Linuxx64SmokeTest + displayName: Linux (Smoke Tests) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: true - - stage: macOS - dependsOn: - - Compile - pool: - vmImage: macOS-latest - variables: - BUILDSECMON_OPT_IN: true - jobs: - - job: macOSUnitTest - displayName: Unit Tests - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: darwin/product-build-darwin.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: true - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: false - - job: macOSIntegrationTest - displayName: Integration Tests - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: darwin/product-build-darwin.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: true - VSCODE_RUN_SMOKE_TESTS: false - - job: macOSSmokeTest - displayName: Smoke Tests - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: darwin/product-build-darwin.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: true + - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: + - job: Linuxx64MaintainNodeModulesCache + displayName: Linux (Maintain node_modules cache) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + steps: + - template: product-build-pr-cache.yml + + # - job: macOSUnitTest + # displayName: macOS (Unit Tests) + # pool: + # vmImage: macOS-latest + # timeoutInMinutes: 60 + # variables: + # BUILDSECMON_OPT_IN: true + # VSCODE_ARCH: x64 + # steps: + # - template: darwin/product-build-darwin.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: true + # VSCODE_RUN_INTEGRATION_TESTS: false + # VSCODE_RUN_SMOKE_TESTS: false + # - job: macOSIntegrationTest + # displayName: macOS (Integration Tests) + # pool: + # vmImage: macOS-latest + # timeoutInMinutes: 60 + # variables: + # BUILDSECMON_OPT_IN: true + # VSCODE_ARCH: x64 + # steps: + # - template: darwin/product-build-darwin.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: false + # VSCODE_RUN_INTEGRATION_TESTS: true + # VSCODE_RUN_SMOKE_TESTS: false + # - job: macOSSmokeTest + # displayName: macOS (Smoke Tests) + # pool: + # vmImage: macOS-latest + # timeoutInMinutes: 60 + # variables: + # BUILDSECMON_OPT_IN: true + # VSCODE_ARCH: x64 + # steps: + # - template: darwin/product-build-darwin.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: false + # VSCODE_RUN_INTEGRATION_TESTS: false + # VSCODE_RUN_SMOKE_TESTS: true + + # - job: WindowsUnitTests + # displayName: Windows (Unit Tests) + # pool: vscode-1es-vscode-windows-2019 + # timeoutInMinutes: 60 + # variables: + # VSCODE_ARCH: x64 + # steps: + # - template: win32/product-build-win32.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: true + # VSCODE_RUN_INTEGRATION_TESTS: false + # VSCODE_RUN_SMOKE_TESTS: false + # - job: WindowsIntegrationTests + # displayName: Windows (Integration Tests) + # pool: vscode-1es-vscode-windows-2019 + # timeoutInMinutes: 60 + # variables: + # VSCODE_ARCH: x64 + # steps: + # - template: win32/product-build-win32.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: false + # VSCODE_RUN_INTEGRATION_TESTS: true + # VSCODE_RUN_SMOKE_TESTS: false + # - job: WindowsSmokeTests + # displayName: Windows (Smoke Tests) + # pool: vscode-1es-vscode-windows-2019 + # timeoutInMinutes: 60 + # variables: + # VSCODE_ARCH: x64 + # steps: + # - template: win32/product-build-win32.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: false + # VSCODE_RUN_INTEGRATION_TESTS: false + # VSCODE_RUN_SMOKE_TESTS: true diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 46402a8b7f0..25b0c188196 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -28,7 +28,7 @@ parameters: - name: ENABLE_TERRAPIN displayName: "Enable Terrapin" type: boolean - default: true + default: false - name: VSCODE_BUILD_WIN32 displayName: "🎯 Windows x64" type: boolean @@ -108,9 +108,11 @@ variables: - name: VSCODE_BUILD_STAGE_WINDOWS value: ${{ or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_LINUX - value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true), eq(parameters.VSCODE_BUILD_WEB, true)) }} + value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_MACOS value: ${{ or(eq(parameters.VSCODE_BUILD_MACOS, true), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }} + - name: VSCODE_BUILD_STAGE_WEB + value: ${{ eq(parameters.VSCODE_BUILD_WEB, true) }} - name: VSCODE_CIBUILD value: ${{ in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') }} - name: VSCODE_PUBLISH @@ -176,45 +178,45 @@ stages: pool: vscode-1es-windows jobs: - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: - - job: WindowsUnitTests - displayName: Unit Tests - timeoutInMinutes: 60 - variables: - VSCODE_ARCH: x64 - steps: - - template: win32/product-build-win32.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: true - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: false - - job: WindowsIntegrationTests - displayName: Integration Tests - timeoutInMinutes: 60 - variables: - VSCODE_ARCH: x64 - steps: - - template: win32/product-build-win32.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: true - VSCODE_RUN_SMOKE_TESTS: false - - job: WindowsSmokeTests - displayName: Smoke Tests - timeoutInMinutes: 60 - variables: - VSCODE_ARCH: x64 - steps: - - template: win32/product-build-win32.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: true + - job: WindowsUnitTests + displayName: Unit Tests + timeoutInMinutes: 60 + variables: + VSCODE_ARCH: x64 + steps: + - template: win32/product-build-win32.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: true + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false + - job: WindowsIntegrationTests + displayName: Integration Tests + timeoutInMinutes: 60 + variables: + VSCODE_ARCH: x64 + steps: + - template: win32/product-build-win32.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: true + VSCODE_RUN_SMOKE_TESTS: false + - job: WindowsSmokeTests + displayName: Smoke Tests + timeoutInMinutes: 60 + variables: + VSCODE_ARCH: x64 + steps: + - template: win32/product-build-win32.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: true - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32, true)) }}: - job: Windows @@ -291,51 +293,51 @@ stages: pool: vscode-1es-linux jobs: - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: - - job: Linuxx64UnitTest - displayName: Unit Tests - container: vscode-bionic-x64 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: true - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: false - - job: Linuxx64IntegrationTest - displayName: Integration Tests - container: vscode-bionic-x64 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: true - VSCODE_RUN_SMOKE_TESTS: false - - job: Linuxx64SmokeTest - displayName: Smoke Tests - container: vscode-bionic-x64 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: true + - job: Linuxx64UnitTest + displayName: Unit Tests + container: vscode-bionic-x64 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: true + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false + - job: Linuxx64IntegrationTest + displayName: Integration Tests + container: vscode-bionic-x64 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: true + VSCODE_RUN_SMOKE_TESTS: false + - job: Linuxx64SmokeTest + displayName: Smoke Tests + container: vscode-bionic-x64 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: true - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX, true)) }}: - job: Linuxx64 @@ -430,13 +432,6 @@ stages: steps: - template: linux/product-build-alpine.yml - - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WEB, true)) }}: - - job: LinuxWeb - variables: - VSCODE_ARCH: x64 - steps: - - template: web/product-build-web.yml - - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_MACOS'], true)) }}: - stage: macOS dependsOn: @@ -447,62 +442,8 @@ stages: BUILDSECMON_OPT_IN: true jobs: - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: - - job: macOSUnitTest - displayName: Unit Tests - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: darwin/product-build-darwin.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: true - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: false - - job: macOSIntegrationTest - displayName: Integration Tests - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: darwin/product-build-darwin.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: true - VSCODE_RUN_SMOKE_TESTS: false - - job: macOSSmokeTest - displayName: Smoke Tests - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: darwin/product-build-darwin.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: true - - - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS, true)) }}: - - job: macOS - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: darwin/product-build-darwin.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: false - - - ${{ if eq(parameters.VSCODE_STEP_ON_IT, false) }}: - - job: macOSTest + - job: macOSUnitTest + displayName: Unit Tests timeoutInMinutes: 90 variables: VSCODE_ARCH: x64 @@ -511,19 +452,73 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - - - ${{ if eq(variables['VSCODE_PUBLISH'], true) }}: - - job: macOSSign - dependsOn: - - macOS + VSCODE_RUN_UNIT_TESTS: true + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false + - job: macOSIntegrationTest + displayName: Integration Tests timeoutInMinutes: 90 variables: VSCODE_ARCH: x64 steps: - - template: darwin/product-build-darwin-sign.yml + - template: darwin/product-build-darwin.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: true + VSCODE_RUN_SMOKE_TESTS: false + - job: macOSSmokeTest + displayName: Smoke Tests + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: x64 + steps: + - template: darwin/product-build-darwin.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: true + + - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS, true)) }}: + - job: macOS + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: x64 + steps: + - template: darwin/product-build-darwin.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false + + - ${{ if eq(parameters.VSCODE_STEP_ON_IT, false) }}: + - job: macOSTest + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: x64 + steps: + - template: darwin/product-build-darwin.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} + VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} + VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} + + - ${{ if eq(variables['VSCODE_PUBLISH'], true) }}: + - job: macOSSign + dependsOn: + - macOS + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: x64 + steps: + - template: darwin/product-build-darwin-sign.yml - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}: - job: macOSARM64 @@ -570,6 +565,19 @@ stages: steps: - template: darwin/product-build-darwin-sign.yml + - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WEB'], true)) }}: + - stage: Web + dependsOn: + - Compile + pool: vscode-1es-linux + jobs: + - ${{ if eq(parameters.VSCODE_BUILD_WEB, true) }}: + - job: Web + variables: + VSCODE_ARCH: x64 + steps: + - template: web/product-build-web.yml + - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), ne(variables['VSCODE_PUBLISH'], 'false')) }}: - stage: Publish dependsOn: diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 1fd9b0441de..2b5bdc5b53a 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -46,6 +46,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags # using `genericNodeModules` instead of `nodeModules` here to avoid sharing the cache with builds running inside containers @@ -56,6 +57,13 @@ steps: cacheHitVar: NODE_MODULES_RESTORED displayName: Restore node_modules cache + # Cache built-in extensions to avoid GH rate limits. + - task: Cache@2 + inputs: + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions + - script: | set -e tar -xzf .build/node_modules_cache/cache.tgz @@ -94,6 +102,13 @@ steps: displayName: Install dependencies condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + - script: | + set -e + node build/lib/builtInExtensions.js + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + - script: | set -e node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt @@ -116,12 +131,13 @@ steps: GITHUB_TOKEN: "$(github-distro-mixin-password)" displayName: Compile & Hygiene - - script: | - set -e - yarn --cwd test/smoke compile - yarn --cwd test/integration/browser compile - displayName: Compile test suites - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + yarn --cwd test/smoke compile + yarn --cwd test/integration/browser compile + displayName: Compile test suites + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - task: AzureCLI@2 @@ -151,16 +167,18 @@ steps: ./build/azure-pipelines/common/extract-telemetry.sh displayName: Extract Telemetry - - script: | - set -e - tar -cz --ignore-failed-read -f $(Build.ArtifactStagingDirectory)/compilation.tar.gz .build out-* test/integration/browser/out test/smoke/out test/automation/out - displayName: Compress compilation artifact + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + tar -cz --ignore-failed-read -f $(Build.ArtifactStagingDirectory)/compilation.tar.gz .build out-* test/integration/browser/out test/smoke/out test/automation/out + displayName: Compress compilation artifact - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz - artifactName: Compilation - displayName: Publish compilation artifact + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: PublishPipelineArtifact@1 + inputs: + targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz + artifactName: Compilation + displayName: Publish compilation artifact - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - script: | diff --git a/build/azure-pipelines/product-publish.ps1 b/build/azure-pipelines/product-publish.ps1 index 5abfed48dca..5006ec61a30 100644 --- a/build/azure-pipelines/product-publish.ps1 +++ b/build/azure-pipelines/product-publish.ps1 @@ -46,6 +46,7 @@ $stages = @( if ($env:VSCODE_BUILD_STAGE_WINDOWS -eq 'True') { 'Windows' } if ($env:VSCODE_BUILD_STAGE_LINUX -eq 'True') { 'Linux' } if ($env:VSCODE_BUILD_STAGE_MACOS -eq 'True') { 'macOS' } + if ($env:VSCODE_BUILD_STAGE_WEB -eq 'True') { 'Web' } ) do { diff --git a/build/azure-pipelines/product-publish.yml b/build/azure-pipelines/product-publish.yml index 4d711aba120..80076fd666d 100644 --- a/build/azure-pipelines/product-publish.yml +++ b/build/azure-pipelines/product-publish.yml @@ -109,6 +109,7 @@ steps: if ($env:VSCODE_BUILD_STAGE_WINDOWS -eq 'True') { 'Windows' } if ($env:VSCODE_BUILD_STAGE_LINUX -eq 'True') { 'Linux' } if ($env:VSCODE_BUILD_STAGE_MACOS -eq 'True') { 'macOS' } + if ($env:VSCODE_BUILD_STAGE_WEB -eq 'True') { 'Web' } ) Write-Host "Stages to check: $stages" diff --git a/build/azure-pipelines/upload-nlsmetadata.js b/build/azure-pipelines/upload-nlsmetadata.js index fd69b9a8c36..c92cd277d85 100644 --- a/build/azure-pipelines/upload-nlsmetadata.js +++ b/build/azure-pipelines/upload-nlsmetadata.js @@ -20,6 +20,7 @@ function main() { .pipe(merge({ fileName: 'combined.nls.metadata.json', jsonSpace: '', + concatArrays: true, edit: (parsedJson, file) => { if (file.base === 'out-vscode-web-min') { return { vscode: parsedJson }; diff --git a/build/azure-pipelines/upload-nlsmetadata.ts b/build/azure-pipelines/upload-nlsmetadata.ts index 100f5d9cfd5..4749e1f9605 100644 --- a/build/azure-pipelines/upload-nlsmetadata.ts +++ b/build/azure-pipelines/upload-nlsmetadata.ts @@ -33,6 +33,7 @@ function main(): Promise { .pipe(merge({ fileName: 'combined.nls.metadata.json', jsonSpace: '', + concatArrays: true, edit: (parsedJson, file) => { if (file.base === 'out-vscode-web-min') { return { vscode: parsedJson }; diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index 376f14c6bc6..61e409d4859 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -49,6 +49,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js "web" $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -58,6 +59,12 @@ steps: cacheHitVar: NODE_MODULES_RESTORED displayName: Restore node_modules cache + - task: Cache@2 + inputs: + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions + - script: | set -e tar -xzf .build/node_modules_cache/cache.tgz @@ -89,6 +96,13 @@ steps: displayName: Install dependencies condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + - script: | + set -e + node build/lib/builtInExtensions.js + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + - script: | set -e node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt diff --git a/build/azure-pipelines/win32/product-build-win32-test.yml b/build/azure-pipelines/win32/product-build-win32-test.yml index 4b846b1bada..23c2d43a1cc 100644 --- a/build/azure-pipelines/win32/product-build-win32-test.yml +++ b/build/azure-pipelines/win32/product-build-win32-test.yml @@ -1,4 +1,6 @@ parameters: + - name: VSCODE_QUALITY + type: string - name: VSCODE_RUN_UNIT_TESTS type: boolean - name: VSCODE_RUN_INTEGRATION_TESTS @@ -15,29 +17,51 @@ steps: displayName: Download Electron and Playwright - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn electron $(VSCODE_ARCH) } - exec { .\scripts\test.bat --build --tfs "Unit Tests" } - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn electron $(VSCODE_ARCH) } + exec { .\scripts\test.bat --tfs "Unit Tests" } + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 - - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn test-node --build } - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn test-node } + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 - - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn test-browser-no-install --sequential --build --browser chromium --browser firefox --tfs "Browser Unit Tests" } - displayName: Run unit tests (Browser, Chromium & Firefox) - timeoutInMinutes: 20 + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node test/unit/browser/index.js --sequential --browser chromium --tfs "Browser Unit Tests" } + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 20 + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn electron $(VSCODE_ARCH) } + exec { .\scripts\test.bat --build --tfs "Unit Tests" } + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn test-node --build } + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn test-browser-no-install --sequential --build --browser chromium --tfs "Browser Unit Tests" } + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 20 - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - powershell: | @@ -52,6 +76,7 @@ steps: compile-extension:html-language-features-server ` compile-extension:ipynb ` compile-extension:json-language-features-server ` + compile-extension:markdown-language-features-server ` compile-extension:markdown-language-features ` compile-extension-media ` compile-extension:microsoft-authentication ` @@ -63,38 +88,58 @@ steps: } displayName: Build integration tests - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - powershell: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json - $AppNameShort = $AppProductJson.nameShort - exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-integration.bat --build --tfs "Integration Tests" } - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { .\scripts\test-integration.bat --tfs "Integration Tests" } + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; .\scripts\test-web-integration.bat --browser firefox } - displayName: Run integration tests (Browser, Firefox) - timeoutInMinutes: 20 + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { .\scripts\test-web-integration.bat --browser firefox } + displayName: Run integration tests (Browser, Firefox) + timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json - $AppNameShort = $AppProductJson.nameShort - exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-remote-integration.bat } - displayName: Run integration tests (Remote) - timeoutInMinutes: 20 + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { .\scripts\test-remote-integration.bat } + displayName: Run integration tests (Remote) + timeoutInMinutes: 20 + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json + $AppNameShort = $AppProductJson.nameShort + exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-integration.bat --build --tfs "Integration Tests" } + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; .\scripts\test-web-integration.bat --browser firefox } + displayName: Run integration tests (Browser, Firefox) + timeoutInMinutes: 20 + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json + $AppNameShort = $AppProductJson.nameShort + exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-remote-integration.bat } + displayName: Run integration tests (Remote) + timeoutInMinutes: 20 - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - powershell: | @@ -104,36 +149,47 @@ steps: continueOnError: true condition: succeededOrFailed() - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)" - exec { yarn smoketest-no-compile --web --tracing --headless } - displayName: Run smoke tests (Browser, Chromium) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn --cwd test/smoke compile } + displayName: Compile smoke tests - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - exec { yarn smoketest-no-compile --tracing --build "$AppRoot" } - displayName: Run smoke tests (Electron) - timeoutInMinutes: 20 + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn smoketest-no-compile --tracing } + displayName: Run smoke tests (Electron) + timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)" - exec { yarn gulp compile-extension:vscode-test-resolver } - exec { yarn smoketest-no-compile --tracing --remote --build "$AppRoot" } - displayName: Run smoke tests (Remote) - timeoutInMinutes: 20 + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + exec { yarn smoketest-no-compile --tracing --build "$AppRoot" } + displayName: Run smoke tests (Electron) + timeoutInMinutes: 20 + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)" + exec { yarn smoketest-no-compile --web --tracing --headless } + displayName: Run smoke tests (Browser, Chromium) + timeoutInMinutes: 20 + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)" + exec { yarn gulp compile-extension:vscode-test-resolver } + exec { yarn smoketest-no-compile --tracing --remote --build "$AppRoot" } + displayName: Run smoke tests (Remote) + timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - powershell: | . build/azure-pipelines/win32/exec.ps1 exec {.\build\azure-pipelines\win32\listprocesses.bat } @@ -155,7 +211,6 @@ steps: continueOnError: true condition: failed() - - ${{ if or(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: # In order to properly symbolify above crash reports # (if any), we need the compiled native modules too - task: PublishPipelineArtifact@0 @@ -171,7 +226,6 @@ steps: continueOnError: true condition: failed() - - ${{ if or(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - task: PublishPipelineArtifact@0 inputs: targetPath: .build\logs diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 65504f03ecd..751daf543af 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -11,6 +11,11 @@ parameters: type: boolean steps: + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 + - task: NodeTool@0 inputs: versionSpec: "16.x" @@ -28,17 +33,19 @@ steps: KeyVaultName: vscode SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" - - task: DownloadPipelineArtifact@2 - inputs: - artifact: Compilation - path: $(Build.ArtifactStagingDirectory) - displayName: Download compilation output + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: Compilation + path: $(Build.ArtifactStagingDirectory) + displayName: Download compilation output - - task: ExtractFiles@1 - displayName: Extract compilation output - inputs: - archiveFilePatterns: "$(Build.ArtifactStagingDirectory)/compilation.tar.gz" - cleanDestinationFolder: false + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: ExtractFiles@1 + displayName: Extract compilation output + inputs: + archiveFilePatterns: "$(Build.ArtifactStagingDirectory)/compilation.tar.gz" + cleanDestinationFolder: false - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - powershell: | @@ -69,9 +76,11 @@ steps: displayName: Merge distro - powershell: | + if (!(Test-Path ".build")) { New-Item -Path ".build" -ItemType Directory } "$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch "$env:ENABLE_TERRAPIN" | Out-File -Encoding ascii -NoNewLine .build\terrapin node build/azure-pipelines/common/computeNodeModulesCacheKey.js > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -81,6 +90,12 @@ steps: cacheHitVar: NODE_MODULES_RESTORED displayName: Restore node_modules cache + - task: Cache@2 + inputs: + key: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions + - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" @@ -111,6 +126,14 @@ steps: displayName: Install dependencies condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/lib/builtInExtensions.js } + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + displayName: Download missing built-in extensions + - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" @@ -127,20 +150,30 @@ steps: exec { node build/azure-pipelines/mixin } displayName: Mix in quality - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build\lib\policies } - displayName: Generate Group Policy definitions - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build\lib\policies } + displayName: Generate Group Policy definitions + retryCountOnTaskFailure: 3 - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-min-ci" } - echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)" - displayName: Build + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + exec { yarn gulp "transpile-client-swc" "transpile-extensions" } + displayName: Transpile + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-min-ci" } + echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)" + displayName: Build - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - powershell: | @@ -158,19 +191,21 @@ steps: displayName: Mix in quality condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - exec { yarn gulp "vscode-reh-win32-$(VSCODE_ARCH)-min-ci" } - exec { yarn gulp "vscode-reh-web-win32-$(VSCODE_ARCH)-min-ci" } - echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(CodeSigningFolderPath),$(agent.builddirectory)/vscode-reh-win32-$(VSCODE_ARCH)" - displayName: Build Server - condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + exec { yarn gulp "vscode-reh-win32-$(VSCODE_ARCH)-min-ci" } + exec { yarn gulp "vscode-reh-web-win32-$(VSCODE_ARCH)-min-ci" } + echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(CodeSigningFolderPath),$(agent.builddirectory)/vscode-reh-win32-$(VSCODE_ARCH)" + displayName: Build Server + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - template: product-build-win32-test.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} diff --git a/build/eslint.js b/build/eslint.js index c04f4ef7756..288917b35bf 100644 --- a/build/eslint.js +++ b/build/eslint.js @@ -13,8 +13,7 @@ function eslint() { .src(eslintFilter, { base: '.', follow: true, allowEmpty: true }) .pipe( gulpeslint({ - configFile: '.eslintrc.json', - rulePaths: ['./build/lib/eslint'], + configFile: '.eslintrc.json' }) ) .pipe(gulpeslint.formatEach('compact')) diff --git a/build/filters.js b/build/filters.js index 2042cf58e49..daddf2ed350 100644 --- a/build/filters.js +++ b/build/filters.js @@ -39,6 +39,7 @@ module.exports.unicodeFilter = [ '!**/test/**', '!**/*.test.ts', '!**/*.{d.ts,json,md}', + '!**/*.mp3', '!build/win32/**', '!extensions/markdown-language-features/notebook-out/*.js', @@ -65,6 +66,7 @@ module.exports.indentationFilter = [ '!**/LICENSE.{txt,rtf}', '!LICENSES.chromium.html', '!**/LICENSE', + '!**/*.mp3', '!src/vs/loader.js', '!src/vs/base/browser/dompurify/*', '!src/vs/base/common/marked/marked.js', @@ -135,10 +137,12 @@ module.exports.copyrightFilter = [ '!**/*.cmd', '!**/*.ico', '!**/*.opus', + '!**/*.mp3', '!**/*.icns', '!**/*.xml', '!**/*.sh', '!**/*.zsh', + '!**/*.fish', '!**/*.txt', '!**/*.xpm', '!**/*.opts', diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index a07071e345d..727b14eb267 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -53,6 +53,7 @@ const compilations = [ 'json-language-features/client/tsconfig.json', 'json-language-features/server/tsconfig.json', 'markdown-language-features/preview-src/tsconfig.json', + 'markdown-language-features/server/tsconfig.json', 'markdown-language-features/tsconfig.json', 'markdown-math/tsconfig.json', 'merge-conflict/tsconfig.json', @@ -109,7 +110,7 @@ const tasks = compilations.map(function (tsconfigFile) { overrideOptions.inlineSources = Boolean(build); overrideOptions.base = path.dirname(absolutePath); - const compilation = tsb.create(absolutePath, overrideOptions, { verbose: false, transpileOnly, transpileOnlyIncludesDts: transpileOnly }, err => reporter(err.toString())); + const compilation = tsb.create(absolutePath, overrideOptions, { verbose: false, transpileOnly, transpileOnlyIncludesDts: transpileOnly, transpileWithSwc: true }, err => reporter(err.toString())); const pipeline = function () { const input = es.through(); @@ -235,8 +236,8 @@ exports.compileExtensionMediaBuildTask = compileExtensionMediaBuildTask; const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions')); const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series( cleanExtensionsBuildTask, + task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false).pipe(gulp.dest('.build'))), task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream(false).pipe(gulp.dest('.build'))), - task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false, product.extensionsGallery?.serviceUrl).pipe(gulp.dest('.build'))), )); gulp.task(compileExtensionsBuildTask); diff --git a/build/gulpfile.js b/build/gulpfile.js index 595cace0b24..e945c06eed4 100644 --- a/build/gulpfile.js +++ b/build/gulpfile.js @@ -11,7 +11,7 @@ require('events').EventEmitter.defaultMaxListeners = 100; const gulp = require('gulp'); const util = require('./lib/util'); const task = require('./lib/task'); -const { transpileTask, compileTask, watchTask, compileApiProposalNamesTask, watchApiProposalNamesTask } = require('./lib/compilation'); +const { transpileClientSWC, transpileTask, compileTask, watchTask, compileApiProposalNamesTask, watchApiProposalNamesTask } = require('./lib/compilation'); const { monacoTypecheckTask/* , monacoTypecheckWatchTask */ } = require('./gulpfile.editor'); const { compileExtensionsTask, watchExtensionsTask, compileExtensionMediaTask } = require('./gulpfile.extensions'); @@ -19,6 +19,10 @@ const { compileExtensionsTask, watchExtensionsTask, compileExtensionMediaTask } gulp.task(compileApiProposalNamesTask); gulp.task(watchApiProposalNamesTask); +// SWC Client Transpile +const transpileClientSWCTask = task.define('transpile-client-swc', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), transpileTask('src', 'out', true))); +gulp.task(transpileClientSWCTask); + // Transpile only const transpileClientTask = task.define('transpile-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), transpileTask('src', 'out'))); gulp.task(transpileClientTask); diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 2abc3f30c43..a07c55232de 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -76,12 +76,14 @@ const serverResources = [ 'out-build/vs/base/node/ps.sh', // Terminal shell integration + 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration.fish', 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1', 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh', 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-env.zsh', 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-profile.zsh', 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh', 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh', + 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration.fish', '!**/test/**' ]; diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 4a47b63c823..d371e6f3c25 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -6,6 +6,7 @@ 'use strict'; const gulp = require('gulp'); +const merge = require('gulp-merge-json'); const fs = require('fs'); const os = require('os'); const cp = require('child_process'); @@ -33,6 +34,9 @@ const minimist = require('minimist'); const { compileBuildTask } = require('./gulpfile.compile'); const { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require('./gulpfile.extensions'); const { getSettingsSearchBuildId, shouldSetupSettingsSearch } = require('./azure-pipelines/upload-configuration'); +const { promisify } = require('util'); +const glob = promisify(require('glob')); +const rcedit = promisify(require('rcedit')); // Build const vscodeEntryPoints = _.flatten([ @@ -55,7 +59,7 @@ const vscodeResources = [ 'out-build/bootstrap-amd.js', 'out-build/bootstrap-node.js', 'out-build/bootstrap-window.js', - 'out-build/vs/**/*.{svg,png,html,jpg,opus}', + 'out-build/vs/**/*.{svg,png,html,jpg,mp3}', '!out-build/vs/code/browser/**/*.html', '!out-build/vs/editor/standalone/**/*.svg', 'out-build/vs/base/common/performance.js', @@ -68,6 +72,7 @@ const vscodeResources = [ 'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/contrib/debug/**/*.json', 'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt', + 'out-build/vs/workbench/contrib/terminal/browser/media/*.fish', 'out-build/vs/workbench/contrib/terminal/browser/media/*.ps1', 'out-build/vs/workbench/contrib/terminal/browser/media/*.sh', 'out-build/vs/workbench/contrib/terminal/browser/media/*.zsh', @@ -76,7 +81,7 @@ const vscodeResources = [ 'out-build/vs/workbench/contrib/tasks/**/*.json', 'out-build/vs/platform/files/**/*.exe', 'out-build/vs/platform/files/**/*.md', - 'out-build/vs/code/electron-browser/workbench/**', + 'out-build/vs/code/electron-sandbox/workbench/**', 'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js', 'out-build/vs/code/electron-sandbox/issue/issueReporter.js', 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.js', @@ -165,8 +170,8 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op 'vs/workbench/workbench.desktop.main.js', 'vs/workbench/workbench.desktop.main.css', 'vs/workbench/api/node/extensionHostProcess.js', - 'vs/code/electron-browser/workbench/workbench.html', - 'vs/code/electron-browser/workbench/workbench.js' + 'vs/code/electron-sandbox/workbench/workbench.html', + 'vs/code/electron-sandbox/workbench/workbench.js' ]); const src = gulp.src(out + '/**', { base: '.' }) @@ -345,6 +350,35 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op }; } +function patchWin32DependenciesTask(destinationFolderName) { + const cwd = path.join(path.dirname(root), destinationFolderName); + + return async () => { + const deps = await glob('**/*.node', { cwd }); + const packageJson = JSON.parse(await fs.promises.readFile(path.join(cwd, 'resources', 'app', 'package.json'), 'utf8')); + const product = JSON.parse(await fs.promises.readFile(path.join(cwd, 'resources', 'app', 'product.json'), 'utf8')); + const baseVersion = packageJson.version.replace(/-.*$/, ''); + + await Promise.all(deps.map(async dep => { + const basename = path.basename(dep); + + await rcedit(path.join(cwd, dep), { + 'file-version': baseVersion, + 'version-string': { + 'CompanyName': 'Microsoft Corporation', + 'FileDescription': product.nameLong, + 'FileVersion': packageJson.version, + 'InternalName': basename, + 'LegalCopyright': 'Copyright (C) 2022 Microsoft. All rights reserved', + 'OriginalFilename': basename, + 'ProductName': product.nameLong, + 'ProductVersion': packageJson.version, + } + }); + })); + }; +} + const buildRoot = path.dirname(root); const BUILD_TARGETS = [ @@ -368,10 +402,16 @@ BUILD_TARGETS.forEach(buildTarget => { const sourceFolderName = `out-vscode${dashed(minified)}`; const destinationFolderName = `VSCode${dashed(platform)}${dashed(arch)}`; - const vscodeTaskCI = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}-ci`, task.series( + const tasks = [ util.rimraf(path.join(buildRoot, destinationFolderName)), packageTask(platform, arch, sourceFolderName, destinationFolderName, opts) - )); + ]; + + if (platform === 'win32') { + tasks.push(patchWin32DependenciesTask(destinationFolderName)); + } + + const vscodeTaskCI = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}-ci`, task.series(...tasks)); gulp.task(vscodeTaskCI); const vscodeTask = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series( @@ -392,6 +432,8 @@ BUILD_TARGETS.forEach(buildTarget => { } }); +// #region nls + const innoSetupConfig = { 'zh-cn': { codePage: 'CP936', defaultInfo: { name: 'Simplified Chinese', id: '$0804', } }, 'zh-tw': { codePage: 'CP950', defaultInfo: { name: 'Traditional Chinese', id: '$0404' } }, @@ -407,46 +449,23 @@ const innoSetupConfig = { 'tr': { codePage: 'CP1254' } }; -// Transifex Localizations - -const apiHostname = process.env.TRANSIFEX_API_URL; -const apiName = process.env.TRANSIFEX_API_NAME; -const apiToken = process.env.TRANSIFEX_API_TOKEN; - -gulp.task(task.define( - 'vscode-translations-push', - task.series( - compileBuildTask, - compileExtensionsBuildTask, - optimizeVSCodeTask, - function () { - const pathToMetadata = './out-vscode/nls.metadata.json'; - const pathToExtensions = '.build/extensions/*'; - const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}'; - - return es.merge( - gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()), - gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()), - gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions()) - ).pipe(i18n.findObsoleteResources(apiHostname, apiName, apiToken) - ).pipe(i18n.pushXlfFiles(apiHostname, apiName, apiToken)); - } - ) -)); - gulp.task(task.define( 'vscode-translations-export', task.series( - compileBuildTask, + core, compileExtensionsBuildTask, - optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; + const pathToRehWebMetadata = './out-vscode-reh-web/nls.metadata.json'; const pathToExtensions = '.build/extensions/*'; const pathToSetup = 'build/win32/i18n/messages.en.isl'; return es.merge( - gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()), + gulp.src([pathToMetadata, pathToRehWebMetadata]).pipe(merge({ + fileName: 'nls.metadata.json', + jsonSpace: '', + concatArrays: true + })).pipe(i18n.createXlfFilesForCoreBundle()), gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()), gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions()) ).pipe(vfs.dest('../vscode-translations-export')); @@ -454,13 +473,6 @@ gulp.task(task.define( ) )); -gulp.task('vscode-translations-pull', function () { - return es.merge([...i18n.defaultLanguages, ...i18n.extraLanguages].map(language => { - const includeDefault = !!innoSetupConfig[language.id].defaultInfo; - return i18n.pullSetupXlfFiles(apiHostname, apiName, apiToken, language, includeDefault).pipe(vfs.dest(`../vscode-translations-import/${language.id}/setup`)); - })); -}); - gulp.task('vscode-translations-import', function () { const options = minimist(process.argv.slice(2), { string: 'location', @@ -475,3 +487,5 @@ gulp.task('vscode-translations-import', function () { .pipe(vfs.dest(`./build/win32/i18n`)); })); }); + +// #endregion diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 7d0f70f9bef..4a25ca5ab04 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -15,13 +15,18 @@ const util = require('./lib/util'); const task = require('./lib/task'); const packageJson = require('../package.json'); const product = require('../product.json'); -const rpmDependenciesGenerator = require('./linux/rpm/dependencies-generator'); +const dependenciesGenerator = require('./linux/dependencies-generator'); +const sysrootInstaller = require('./linux/debian/install-sysroot'); +const debianRecommendedDependencies = require('./linux/debian/dep-lists').recommendedDeps; const path = require('path'); const root = path.dirname(__dirname); const commit = util.getVersion(root); const linuxPackageRevision = Math.floor(new Date().getTime() / 1000); +/** + * @param {string} arch + */ function getDebPackageArch(arch) { return { x64: 'amd64', armhf: 'armhf', arm64: 'arm64' }[arch]; } @@ -74,12 +79,16 @@ function prepareDebPackage(arch) { let size = 0; const control = code.pipe(es.through( function (f) { size += f.isDirectory() ? 4096 : f.contents.length; }, - function () { + async function () { const that = this; + const sysroot = await sysrootInstaller.getSysroot(debArch); + const dependencies = dependenciesGenerator.getDependencies('deb', binaryDir, product.applicationName, debArch, sysroot); gulp.src('resources/linux/debian/control.template', { base: '.' }) .pipe(replace('@@NAME@@', product.applicationName)) .pipe(replace('@@VERSION@@', packageJson.version + '-' + linuxPackageRevision)) .pipe(replace('@@ARCHITECTURE@@', debArch)) + .pipe(replace('@@DEPENDS@@', dependencies.join(', '))) + .pipe(replace('@@RECOMMENDS@@', debianRecommendedDependencies.join(', '))) .pipe(replace('@@INSTALLEDSIZE@@', Math.ceil(size / 1024))) .pipe(rename('DEBIAN/control')) .pipe(es.through(function (f) { that.emit('data', f); }, function () { that.emit('end'); })); @@ -176,7 +185,7 @@ function prepareRpmPackage(arch) { const code = gulp.src(binaryDir + '/**/*', { base: binaryDir }) .pipe(rename(function (p) { p.dirname = 'BUILD/usr/share/' + product.applicationName + '/' + p.dirname; })); - const dependencies = rpmDependenciesGenerator.getDependencies(binaryDir, product.applicationName, rpmArch); + const dependencies = dependenciesGenerator.getDependencies('rpm', binaryDir, product.applicationName, rpmArch); const spec = gulp.src('resources/linux/rpm/code.spec.template', { base: '.' }) .pipe(replace('@@NAME@@', product.applicationName)) .pipe(replace('@@NAME_LONG@@', product.nameLong)) @@ -210,7 +219,7 @@ function buildRpmPackage(arch) { return shell.task([ 'mkdir -p ' + destination, - 'HOME="$(pwd)/' + destination + '" fakeroot rpmbuild -bb ' + rpmBuildPath + '/SPECS/' + product.applicationName + '.spec --target=' + rpmArch, + 'HOME="$(pwd)/' + destination + '" rpmbuild -bb ' + rpmBuildPath + '/SPECS/' + product.applicationName + '.spec --target=' + rpmArch, 'cp "' + rpmOut + '/$(ls ' + rpmOut + ')" ' + destination + '/' ]); } diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index 4c1259c241c..8e92d7717ab 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -32,7 +32,7 @@ const version = (quality && quality !== 'stable') ? `${packageJson.version}-${qu const vscodeWebResourceIncludes = [ // Workbench - 'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,jpg,opus}', + 'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,jpg,mp3}', 'out-build/vs/code/browser/workbench/*.html', 'out-build/vs/base/browser/ui/codicons/codicon/**/*.ttf', 'out-build/vs/**/markdown.css', @@ -229,7 +229,7 @@ function packageTask(sourceFolderName, destinationFolderName) { const compileWebExtensionsBuildTask = task.define('compile-web-extensions-build', task.series( task.define('clean-web-extensions-build', util.rimraf('.build/web/extensions')), task.define('bundle-web-extensions-build', () => extensions.packageLocalExtensionsStream(true).pipe(gulp.dest('.build/web'))), - task.define('bundle-marketplace-web-extensions-build', () => extensions.packageMarketplaceExtensionsStream(true, product.extensionsGallery?.serviceUrl).pipe(gulp.dest('.build/web'))), + task.define('bundle-marketplace-web-extensions-build', () => extensions.packageMarketplaceExtensionsStream(true).pipe(gulp.dest('.build/web'))), task.define('bundle-web-extension-media-build', () => extensions.buildExtensionMedia(false, '.build/web/extensions')), )); gulp.task(compileWebExtensionsBuildTask); diff --git a/build/hygiene.js b/build/hygiene.js index e18466c8f77..99b757e6d76 100644 --- a/build/hygiene.js +++ b/build/hygiene.js @@ -173,8 +173,7 @@ function hygiene(some, linting = true) { .pipe(filter(eslintFilter)) .pipe( gulpeslint({ - configFile: '.eslintrc.json', - rulePaths: ['./build/lib/eslint'], + configFile: '.eslintrc.json' }) ) .pipe(gulpeslint.formatEach('compact')) diff --git a/build/lib/builtInExtensions.js b/build/lib/builtInExtensions.js index f38871c36d7..38c30234b7e 100644 --- a/build/lib/builtInExtensions.js +++ b/build/lib/builtInExtensions.js @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.getBuiltInExtensions = void 0; +exports.getBuiltInExtensions = exports.getExtensionStream = void 0; const fs = require("fs"); const path = require("path"); const os = require("os"); @@ -44,6 +44,21 @@ function isUpToDate(extension) { return false; } } +function getExtensionDownloadStream(extension) { + const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl; + return (galleryServiceUrl ? ext.fromMarketplace(galleryServiceUrl, extension) : ext.fromGithub(extension)) + .pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`)); +} +function getExtensionStream(extension) { + // if the extension exists on disk, use those files instead of downloading anew + if (isUpToDate(extension)) { + log('[extensions]', `${extension.name}@${extension.version} up to date`, ansiColors.green('✔︎')); + return vfs.src(['**'], { cwd: getExtensionPath(extension), dot: true }) + .pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`)); + } + return getExtensionDownloadStream(extension); +} +exports.getExtensionStream = getExtensionStream; function syncMarketplaceExtension(extension) { const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl; const source = ansiColors.blue(galleryServiceUrl ? '[marketplace]' : '[github]'); @@ -52,8 +67,7 @@ function syncMarketplaceExtension(extension) { return es.readArray([]); } rimraf.sync(getExtensionPath(extension)); - return (galleryServiceUrl ? ext.fromMarketplace(galleryServiceUrl, extension) : ext.fromGithub(extension)) - .pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`)) + return getExtensionDownloadStream(extension) .pipe(vfs.dest('.build/builtInExtensions')) .on('end', () => log(source, extension.name, ansiColors.green('✔︎'))); } diff --git a/build/lib/builtInExtensions.ts b/build/lib/builtInExtensions.ts index 971847c8756..912e05653ac 100644 --- a/build/lib/builtInExtensions.ts +++ b/build/lib/builtInExtensions.ts @@ -68,10 +68,26 @@ function isUpToDate(extension: IExtensionDefinition): boolean { } } +function getExtensionDownloadStream(extension: IExtensionDefinition) { + const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl; + return (galleryServiceUrl ? ext.fromMarketplace(galleryServiceUrl, extension) : ext.fromGithub(extension)) + .pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`)); +} + +export function getExtensionStream(extension: IExtensionDefinition) { + // if the extension exists on disk, use those files instead of downloading anew + if (isUpToDate(extension)) { + log('[extensions]', `${extension.name}@${extension.version} up to date`, ansiColors.green('✔︎')); + return vfs.src(['**'], { cwd: getExtensionPath(extension), dot: true }) + .pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`)); + } + + return getExtensionDownloadStream(extension); +} + function syncMarketplaceExtension(extension: IExtensionDefinition): Stream { const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl; const source = ansiColors.blue(galleryServiceUrl ? '[marketplace]' : '[github]'); - if (isUpToDate(extension)) { log(source, `${extension.name}@${extension.version}`, ansiColors.green('✔︎')); return es.readArray([]); @@ -79,8 +95,7 @@ function syncMarketplaceExtension(extension: IExtensionDefinition): Stream { rimraf.sync(getExtensionPath(extension)); - return (galleryServiceUrl ? ext.fromMarketplace(galleryServiceUrl, extension) : ext.fromGithub(extension)) - .pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`)) + return getExtensionDownloadStream(extension) .pipe(vfs.dest('.build/builtInExtensions')) .on('end', () => log(source, extension.name, ansiColors.green('✔︎'))); } diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 21944c463f9..f5d46d7b20c 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -19,6 +19,7 @@ const os = require("os"); const File = require("vinyl"); const task = require("./task"); const watch = require('./watch'); +// --- gulp-tsb: compile and transpile -------------------------------- const reporter = (0, reporter_1.createReporter)(); function getTypeScriptCompilerOptions(src) { const rootDir = path.join(__dirname, `../../${src}`); @@ -42,7 +43,11 @@ function createCompile(src, build, emitError, transpileOnly) { if (!build) { overrideOptions.inlineSourceMap = true; } - const compilation = tsb.create(projectPath, overrideOptions, { verbose: false, transpileOnly }, err => reporter(err)); + const compilation = tsb.create(projectPath, overrideOptions, { + verbose: false, + transpileOnly: Boolean(transpileOnly), + transpileWithSwc: typeof transpileOnly !== 'boolean' && transpileOnly.swc + }, err => reporter(err)); function pipeline(token) { const bom = require('gulp-bom'); const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path)); @@ -73,9 +78,9 @@ function createCompile(src, build, emitError, transpileOnly) { }; return pipeline; } -function transpileTask(src, out) { +function transpileTask(src, out, swc) { return function () { - const transpile = createCompile(src, false, true, true); + const transpile = createCompile(src, false, true, { swc }); const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); return srcPipe .pipe(transpile()) @@ -188,6 +193,15 @@ class MonacoGenerator { } } function generateApiProposalNames() { + let eol; + try { + const src = fs.readFileSync('src/vs/workbench/services/extensions/common/extensionsApiProposals.ts', 'utf-8'); + const match = /\r?\n/m.exec(src); + eol = match ? match[0] : os.EOL; + } + catch { + eol = os.EOL; + } const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts$/; const proposalNames = new Set(); const input = es.through(); @@ -210,11 +224,11 @@ function generateApiProposalNames() { '// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.', '', 'export const allApiProposals = Object.freeze({', - `${names.map(name => `\t${name}: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.${name}.d.ts'`).join(`,${os.EOL}`)}`, + `${names.map(name => `\t${name}: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.${name}.d.ts'`).join(`,${eol}`)}`, '});', 'export type ApiProposalName = keyof typeof allApiProposals;', '', - ].join(os.EOL); + ].join(eol); this.emit('data', new File({ path: 'vs/workbench/services/extensions/common/extensionsApiProposals.ts', contents: Buffer.from(contents) diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index b737a5e8746..b9769822d73 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -17,9 +17,11 @@ import * as os from 'os'; import ts = require('typescript'); import * as File from 'vinyl'; import * as task from './task'; - const watch = require('./watch'); + +// --- gulp-tsb: compile and transpile -------------------------------- + const reporter = createReporter(); function getTypeScriptCompilerOptions(src: string): ts.CompilerOptions { @@ -37,7 +39,7 @@ function getTypeScriptCompilerOptions(src: string): ts.CompilerOptions { return options; } -function createCompile(src: string, build: boolean, emitError: boolean, transpileOnly: boolean) { +function createCompile(src: string, build: boolean, emitError: boolean, transpileOnly: boolean | { swc: boolean }) { const tsb = require('./tsb') as typeof import('./tsb'); const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps'); @@ -48,7 +50,11 @@ function createCompile(src: string, build: boolean, emitError: boolean, transpil overrideOptions.inlineSourceMap = true; } - const compilation = tsb.create(projectPath, overrideOptions, { verbose: false, transpileOnly }, err => reporter(err)); + const compilation = tsb.create(projectPath, overrideOptions, { + verbose: false, + transpileOnly: Boolean(transpileOnly), + transpileWithSwc: typeof transpileOnly !== 'boolean' && transpileOnly.swc + }, err => reporter(err)); function pipeline(token?: util.ICancellationToken) { const bom = require('gulp-bom') as typeof import('gulp-bom'); @@ -84,11 +90,11 @@ function createCompile(src: string, build: boolean, emitError: boolean, transpil return pipeline; } -export function transpileTask(src: string, out: string): () => NodeJS.ReadWriteStream { +export function transpileTask(src: string, out: string, swc: boolean): () => NodeJS.ReadWriteStream { return function () { - const transpile = createCompile(src, false, true, true); + const transpile = createCompile(src, false, true, { swc }); const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); return srcPipe @@ -226,6 +232,16 @@ class MonacoGenerator { } function generateApiProposalNames() { + let eol: string; + + try { + const src = fs.readFileSync('src/vs/workbench/services/extensions/common/extensionsApiProposals.ts', 'utf-8'); + const match = /\r?\n/m.exec(src); + eol = match ? match[0] : os.EOL; + } catch { + eol = os.EOL; + } + const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts$/; const proposalNames = new Set(); @@ -250,11 +266,11 @@ function generateApiProposalNames() { '// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.', '', 'export const allApiProposals = Object.freeze({', - `${names.map(name => `\t${name}: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.${name}.d.ts'`).join(`,${os.EOL}`)}`, + `${names.map(name => `\t${name}: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.${name}.d.ts'`).join(`,${eol}`)}`, '});', 'export type ApiProposalName = keyof typeof allApiProposals;', '', - ].join(os.EOL); + ].join(eol); this.emit('data', new File({ path: 'vs/workbench/services/extensions/common/extensionsApiProposals.ts', diff --git a/build/lib/electron.js b/build/lib/electron.js index c0d9db20a98..610d5bb6377 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -152,6 +152,7 @@ exports.config = { 'F# script': ['fsx', 'fsscript'], 'SVG document': ['svg', 'svgz'], 'TOML document': 'toml', + 'Swift source code': 'swift', }, 'default'), // Default icon with default name darwinBundleDocumentType([ diff --git a/build/lib/electron.ts b/build/lib/electron.ts index 76ad172e395..c37a0f6eae3 100644 --- a/build/lib/electron.ts +++ b/build/lib/electron.ts @@ -167,6 +167,7 @@ export const config = { 'F# script': ['fsx', 'fsscript'], 'SVG document': ['svg', 'svgz'], 'TOML document': 'toml', + 'Swift source code': 'swift', }, 'default'), // Default icon with default name darwinBundleDocumentType([ diff --git a/build/lib/eslint/code-import-patterns.js b/build/lib/eslint/code-import-patterns.js deleted file mode 100644 index 47cc3063d1c..00000000000 --- a/build/lib/eslint/code-import-patterns.js +++ /dev/null @@ -1,199 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -const path = require("path"); -const minimatch = require("minimatch"); -const utils_1 = require("./utils"); -const REPO_ROOT = path.normalize(path.join(__dirname, '../../../')); -function isLayerAllowRule(option) { - return !!(option.when && option.allow); -} -/** - * Returns the filename relative to the project root and using `/` as separators - */ -function getRelativeFilename(context) { - const filename = path.normalize(context.getFilename()); - return filename.substring(REPO_ROOT.length).replace(/\\/g, '/'); -} -module.exports = new class { - constructor() { - this.meta = { - messages: { - badImport: 'Imports violates \'{{restrictions}}\' restrictions. See https://github.com/microsoft/vscode/wiki/Source-Code-Organization', - badFilename: 'Missing definition in `code-import-patterns` for this file. Define rules at https://github.com/microsoft/vscode/blob/main/.eslintrc.json' - }, - docs: { - url: 'https://github.com/microsoft/vscode/wiki/Source-Code-Organization' - } - }; - this._optionsCache = new WeakMap(); - } - create(context) { - const options = context.options; - const configs = this._processOptions(options); - const relativeFilename = getRelativeFilename(context); - for (const config of configs) { - if (minimatch(relativeFilename, config.target)) { - return (0, utils_1.createImportRuleListener)((node, value) => this._checkImport(context, config, node, value)); - } - } - context.report({ - loc: { line: 1, column: 0 }, - messageId: 'badFilename' - }); - return {}; - } - _processOptions(options) { - if (this._optionsCache.has(options)) { - return this._optionsCache.get(options); - } - function orSegment(variants) { - return (variants.length === 1 ? variants[0] : `{${variants.join(',')}}`); - } - const layerRules = [ - { layer: 'common', deps: orSegment(['common']) }, - { layer: 'worker', deps: orSegment(['common', 'worker']) }, - { layer: 'browser', deps: orSegment(['common', 'browser']), isBrowser: true }, - { layer: 'electron-sandbox', deps: orSegment(['common', 'browser', 'electron-sandbox']), isBrowser: true }, - { layer: 'node', deps: orSegment(['common', 'node']), isNode: true }, - { layer: 'electron-browser', deps: orSegment(['common', 'browser', 'node', 'electron-sandbox', 'electron-browser']), isBrowser: true, isNode: true }, - { layer: 'electron-main', deps: orSegment(['common', 'node', 'electron-main']), isNode: true }, - ]; - let browserAllow = []; - let nodeAllow = []; - let testAllow = []; - for (const option of options) { - if (isLayerAllowRule(option)) { - if (option.when === 'hasBrowser') { - browserAllow = option.allow.slice(0); - } - else if (option.when === 'hasNode') { - nodeAllow = option.allow.slice(0); - } - else if (option.when === 'test') { - testAllow = option.allow.slice(0); - } - } - } - function findLayer(layer) { - for (const layerRule of layerRules) { - if (layerRule.layer === layer) { - return layerRule; - } - } - return null; - } - function generateConfig(layerRule, target, rawRestrictions) { - const restrictions = []; - const testRestrictions = [...testAllow]; - if (layerRule.isBrowser) { - restrictions.push(...browserAllow); - } - if (layerRule.isNode) { - restrictions.push(...nodeAllow); - } - for (const rawRestriction of rawRestrictions) { - let importPattern; - let when = undefined; - if (typeof rawRestriction === 'string') { - importPattern = rawRestriction; - } - else { - importPattern = rawRestriction.pattern; - when = rawRestriction.when; - } - if (typeof when === 'undefined' - || (when === 'hasBrowser' && layerRule.isBrowser) - || (when === 'hasNode' && layerRule.isNode)) { - restrictions.push(importPattern.replace(/\/\~$/, `/${layerRule.deps}/**`)); - testRestrictions.push(importPattern.replace(/\/\~$/, `/test/${layerRule.deps}/**`)); - } - else if (when === 'test') { - testRestrictions.push(importPattern.replace(/\/\~$/, `/${layerRule.deps}/**`)); - testRestrictions.push(importPattern.replace(/\/\~$/, `/test/${layerRule.deps}/**`)); - } - } - testRestrictions.push(...restrictions); - return [ - { - target: target.replace(/\/\~$/, `/${layerRule.layer}/**`), - restrictions: restrictions - }, - { - target: target.replace(/\/\~$/, `/test/${layerRule.layer}/**`), - restrictions: testRestrictions - } - ]; - } - const configs = []; - for (const option of options) { - if (isLayerAllowRule(option)) { - continue; - } - const target = option.target; - const targetIsVS = /^src\/vs\//.test(target); - const restrictions = (typeof option.restrictions === 'string' ? [option.restrictions] : option.restrictions).slice(0); - if (targetIsVS) { - // Always add "vs/nls" - restrictions.push('vs/nls'); - } - if (targetIsVS && option.layer) { - // single layer => simple substitution for /~ - const layerRule = findLayer(option.layer); - if (layerRule) { - const [config, testConfig] = generateConfig(layerRule, target, restrictions); - if (option.test) { - configs.push(testConfig); - } - else { - configs.push(config); - } - } - } - else if (targetIsVS && /\/\~$/.test(target)) { - // generate all layers - for (const layerRule of layerRules) { - const [config, testConfig] = generateConfig(layerRule, target, restrictions); - configs.push(config); - configs.push(testConfig); - } - } - else { - configs.push({ target, restrictions: restrictions.filter(r => typeof r === 'string') }); - } - } - this._optionsCache.set(options, configs); - return configs; - } - _checkImport(context, config, node, importPath) { - // resolve relative paths - if (importPath[0] === '.') { - const relativeFilename = getRelativeFilename(context); - importPath = path.posix.join(path.posix.dirname(relativeFilename), importPath); - if (/^src\/vs\//.test(importPath)) { - // resolve using AMD base url - importPath = importPath.substring('src/'.length); - } - } - const restrictions = config.restrictions; - let matched = false; - for (const pattern of restrictions) { - if (minimatch(importPath, pattern)) { - matched = true; - break; - } - } - if (!matched) { - // None of the restrictions matched - context.report({ - loc: node.loc, - messageId: 'badImport', - data: { - restrictions: restrictions.join(' or ') - } - }); - } - } -}; diff --git a/build/lib/eslint/code-layering.js b/build/lib/eslint/code-layering.js deleted file mode 100644 index bcb413d9db3..00000000000 --- a/build/lib/eslint/code-layering.js +++ /dev/null @@ -1,68 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -const path_1 = require("path"); -const utils_1 = require("./utils"); -module.exports = new class { - constructor() { - this.meta = { - messages: { - layerbreaker: 'Bad layering. You are not allowed to access {{from}} from here, allowed layers are: [{{allowed}}]' - }, - docs: { - url: 'https://github.com/microsoft/vscode/wiki/Source-Code-Organization' - } - }; - } - create(context) { - const fileDirname = (0, path_1.dirname)(context.getFilename()); - const parts = fileDirname.split(/\\|\//); - const ruleArgs = context.options[0]; - let config; - for (let i = parts.length - 1; i >= 0; i--) { - if (ruleArgs[parts[i]]) { - config = { - allowed: new Set(ruleArgs[parts[i]]).add(parts[i]), - disallowed: new Set() - }; - Object.keys(ruleArgs).forEach(key => { - if (!config.allowed.has(key)) { - config.disallowed.add(key); - } - }); - break; - } - } - if (!config) { - // nothing - return {}; - } - return (0, utils_1.createImportRuleListener)((node, path) => { - if (path[0] === '.') { - path = (0, path_1.join)((0, path_1.dirname)(context.getFilename()), path); - } - const parts = (0, path_1.dirname)(path).split(/\\|\//); - for (let i = parts.length - 1; i >= 0; i--) { - const part = parts[i]; - if (config.allowed.has(part)) { - // GOOD - same layer - break; - } - if (config.disallowed.has(part)) { - // BAD - wrong layer - context.report({ - loc: node.loc, - messageId: 'layerbreaker', - data: { - from: part, - allowed: [...config.allowed.keys()].join(', ') - } - }); - break; - } - } - }); - } -}; diff --git a/build/lib/eslint/code-no-look-behind-regex.js b/build/lib/eslint/code-no-look-behind-regex.js deleted file mode 100644 index c7cdf44c181..00000000000 --- a/build/lib/eslint/code-no-look-behind-regex.js +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ -const _positiveLookBehind = /\(\?<=.+/; -const _negativeLookBehind = /\(\? { - const pattern = node.regex?.pattern; - if (_containsLookBehind(pattern)) { - context.report({ - node, - message: 'Look behind assertions are not yet supported in all browsers' - }); - } - }, - // new Regex("...") - ['NewExpression[callee.name="RegExp"] Literal']: (node) => { - if (_containsLookBehind(node.value)) { - context.report({ - node, - message: 'Look behind assertions are not yet supported in all browsers' - }); - } - } - }; - } -}; diff --git a/build/lib/eslint/code-no-nls-in-standalone-editor.js b/build/lib/eslint/code-no-nls-in-standalone-editor.js deleted file mode 100644 index 36782a4b5bc..00000000000 --- a/build/lib/eslint/code-no-nls-in-standalone-editor.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -const path_1 = require("path"); -const utils_1 = require("./utils"); -module.exports = new class NoNlsInStandaloneEditorRule { - constructor() { - this.meta = { - messages: { - noNls: 'Not allowed to import vs/nls in standalone editor modules. Use standaloneStrings.ts' - } - }; - } - create(context) { - const fileName = context.getFilename(); - if (/vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(fileName) - || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(fileName) - || /vs(\/|\\)editor(\/|\\)editor.api/.test(fileName) - || /vs(\/|\\)editor(\/|\\)editor.main/.test(fileName) - || /vs(\/|\\)editor(\/|\\)editor.worker/.test(fileName)) { - return (0, utils_1.createImportRuleListener)((node, path) => { - // resolve relative paths - if (path[0] === '.') { - path = (0, path_1.join)(context.getFilename(), path); - } - if (/vs(\/|\\)nls/.test(path)) { - context.report({ - loc: node.loc, - messageId: 'noNls' - }); - } - }); - } - return {}; - } -}; diff --git a/build/lib/eslint/code-no-standalone-editor.js b/build/lib/eslint/code-no-standalone-editor.js deleted file mode 100644 index c57bd560bcf..00000000000 --- a/build/lib/eslint/code-no-standalone-editor.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -const path_1 = require("path"); -const utils_1 = require("./utils"); -module.exports = new class NoNlsInStandaloneEditorRule { - constructor() { - this.meta = { - messages: { - badImport: 'Not allowed to import standalone editor modules.' - }, - docs: { - url: 'https://github.com/microsoft/vscode/wiki/Source-Code-Organization' - } - }; - } - create(context) { - if (/vs(\/|\\)editor/.test(context.getFilename())) { - // the vs/editor folder is allowed to use the standalone editor - return {}; - } - return (0, utils_1.createImportRuleListener)((node, path) => { - // resolve relative paths - if (path[0] === '.') { - path = (0, path_1.join)(context.getFilename(), path); - } - if (/vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(path) - || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.api/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.main/.test(path) - || /vs(\/|\\)editor(\/|\\)editor.worker/.test(path)) { - context.report({ - loc: node.loc, - messageId: 'badImport' - }); - } - }); - } -}; diff --git a/build/lib/eslint/code-no-test-only.js b/build/lib/eslint/code-no-test-only.js deleted file mode 100644 index 46d144bfcaf..00000000000 --- a/build/lib/eslint/code-no-test-only.js +++ /dev/null @@ -1,17 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -module.exports = new class NoTestOnly { - create(context) { - return { - ['MemberExpression[object.name="test"][property.name="only"]']: (node) => { - return context.report({ - node, - message: 'test.only is a dev-time tool and CANNOT be pushed' - }); - } - }; - } -}; diff --git a/build/lib/eslint/code-no-unexternalized-strings.js b/build/lib/eslint/code-no-unexternalized-strings.js deleted file mode 100644 index 48b591f8d3d..00000000000 --- a/build/lib/eslint/code-no-unexternalized-strings.js +++ /dev/null @@ -1,111 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -var _a; -const experimental_utils_1 = require("@typescript-eslint/experimental-utils"); -function isStringLiteral(node) { - return !!node && node.type === experimental_utils_1.AST_NODE_TYPES.Literal && typeof node.value === 'string'; -} -function isDoubleQuoted(node) { - return node.raw[0] === '"' && node.raw[node.raw.length - 1] === '"'; -} -module.exports = new (_a = class NoUnexternalizedStrings { - constructor() { - this.meta = { - messages: { - doubleQuoted: 'Only use double-quoted strings for externalized strings.', - badKey: 'The key \'{{key}}\' doesn\'t conform to a valid localize identifier.', - duplicateKey: 'Duplicate key \'{{key}}\' with different message value.', - badMessage: 'Message argument to \'{{message}}\' must be a string literal.' - } - }; - } - create(context) { - const externalizedStringLiterals = new Map(); - const doubleQuotedStringLiterals = new Set(); - function collectDoubleQuotedStrings(node) { - if (isStringLiteral(node) && isDoubleQuoted(node)) { - doubleQuotedStringLiterals.add(node); - } - } - function visitLocalizeCall(node) { - // localize(key, message) - const [keyNode, messageNode] = node.arguments; - // (1) - // extract key so that it can be checked later - let key; - if (isStringLiteral(keyNode)) { - doubleQuotedStringLiterals.delete(keyNode); - key = keyNode.value; - } - else if (keyNode.type === experimental_utils_1.AST_NODE_TYPES.ObjectExpression) { - for (const property of keyNode.properties) { - if (property.type === experimental_utils_1.AST_NODE_TYPES.Property && !property.computed) { - if (property.key.type === experimental_utils_1.AST_NODE_TYPES.Identifier && property.key.name === 'key') { - if (isStringLiteral(property.value)) { - doubleQuotedStringLiterals.delete(property.value); - key = property.value.value; - break; - } - } - } - } - } - if (typeof key === 'string') { - let array = externalizedStringLiterals.get(key); - if (!array) { - array = []; - externalizedStringLiterals.set(key, array); - } - array.push({ call: node, message: messageNode }); - } - // (2) - // remove message-argument from doubleQuoted list and make - // sure it is a string-literal - doubleQuotedStringLiterals.delete(messageNode); - if (!isStringLiteral(messageNode)) { - context.report({ - loc: messageNode.loc, - messageId: 'badMessage', - data: { message: context.getSourceCode().getText(node) } - }); - } - } - function reportBadStringsAndBadKeys() { - // (1) - // report all strings that are in double quotes - for (const node of doubleQuotedStringLiterals) { - context.report({ loc: node.loc, messageId: 'doubleQuoted' }); - } - for (const [key, values] of externalizedStringLiterals) { - // (2) - // report all invalid NLS keys - if (!key.match(NoUnexternalizedStrings._rNlsKeys)) { - for (const value of values) { - context.report({ loc: value.call.loc, messageId: 'badKey', data: { key } }); - } - } - // (2) - // report all invalid duplicates (same key, different message) - if (values.length > 1) { - for (let i = 1; i < values.length; i++) { - if (context.getSourceCode().getText(values[i - 1].message) !== context.getSourceCode().getText(values[i].message)) { - context.report({ loc: values[i].call.loc, messageId: 'duplicateKey', data: { key } }); - } - } - } - } - } - return { - ['Literal']: (node) => collectDoubleQuotedStrings(node), - ['ExpressionStatement[directive] Literal:exit']: (node) => doubleQuotedStringLiterals.delete(node), - ['CallExpression[callee.type="MemberExpression"][callee.object.name="nls"][callee.property.name="localize"]:exit']: (node) => visitLocalizeCall(node), - ['CallExpression[callee.name="localize"][arguments.length>=2]:exit']: (node) => visitLocalizeCall(node), - ['Program:exit']: reportBadStringsAndBadKeys, - }; - } - }, - _a._rNlsKeys = /^[_a-zA-Z0-9][ .\-_a-zA-Z0-9]*$/, - _a); diff --git a/build/lib/eslint/code-no-unused-expressions.js b/build/lib/eslint/code-no-unused-expressions.js deleted file mode 100644 index 5d9710072e6..00000000000 --- a/build/lib/eslint/code-no-unused-expressions.js +++ /dev/null @@ -1,119 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ -module.exports = { - meta: { - type: 'suggestion', - docs: { - description: 'disallow unused expressions', - category: 'Best Practices', - recommended: false, - url: 'https://eslint.org/docs/rules/no-unused-expressions' - }, - schema: [ - { - type: 'object', - properties: { - allowShortCircuit: { - type: 'boolean', - default: false - }, - allowTernary: { - type: 'boolean', - default: false - }, - allowTaggedTemplates: { - type: 'boolean', - default: false - } - }, - additionalProperties: false - } - ] - }, - create(context) { - const config = context.options[0] || {}, allowShortCircuit = config.allowShortCircuit || false, allowTernary = config.allowTernary || false, allowTaggedTemplates = config.allowTaggedTemplates || false; - // eslint-disable-next-line jsdoc/require-description - /** - * @param node any node - * @returns whether the given node structurally represents a directive - */ - function looksLikeDirective(node) { - return node.type === 'ExpressionStatement' && - node.expression.type === 'Literal' && typeof node.expression.value === 'string'; - } - // eslint-disable-next-line jsdoc/require-description - /** - * @param predicate ([a] -> Boolean) the function used to make the determination - * @param list the input list - * @returns the leading sequence of members in the given list that pass the given predicate - */ - function takeWhile(predicate, list) { - for (let i = 0; i < list.length; ++i) { - if (!predicate(list[i])) { - return list.slice(0, i); - } - } - return list.slice(); - } - // eslint-disable-next-line jsdoc/require-description - /** - * @param node a Program or BlockStatement node - * @returns the leading sequence of directive nodes in the given node's body - */ - function directives(node) { - return takeWhile(looksLikeDirective, node.body); - } - // eslint-disable-next-line jsdoc/require-description - /** - * @param node any node - * @param ancestors the given node's ancestors - * @returns whether the given node is considered a directive in its current position - */ - function isDirective(node, ancestors) { - const parent = ancestors[ancestors.length - 1], grandparent = ancestors[ancestors.length - 2]; - return (parent.type === 'Program' || parent.type === 'BlockStatement' && - (/Function/u.test(grandparent.type))) && - directives(parent).indexOf(node) >= 0; - } - /** - * Determines whether or not a given node is a valid expression. Recurses on short circuit eval and ternary nodes if enabled by flags. - * @param node any node - * @returns whether the given node is a valid expression - */ - function isValidExpression(node) { - if (allowTernary) { - // Recursive check for ternary and logical expressions - if (node.type === 'ConditionalExpression') { - return isValidExpression(node.consequent) && isValidExpression(node.alternate); - } - } - if (allowShortCircuit) { - if (node.type === 'LogicalExpression') { - return isValidExpression(node.right); - } - } - if (allowTaggedTemplates && node.type === 'TaggedTemplateExpression') { - return true; - } - if (node.type === 'ExpressionStatement') { - return isValidExpression(node.expression); - } - return /^(?:Assignment|OptionalCall|Call|New|Update|Yield|Await|Chain)Expression$/u.test(node.type) || - (node.type === 'UnaryExpression' && ['delete', 'void'].indexOf(node.operator) >= 0); - } - return { - ExpressionStatement(node) { - if (!isValidExpression(node.expression) && !isDirective(node, context.getAncestors())) { - context.report({ node: node, message: `Expected an assignment or function call and instead saw an expression. ${node.expression}` }); - } - } - }; - } -}; diff --git a/build/lib/eslint/code-translation-remind.js b/build/lib/eslint/code-translation-remind.js deleted file mode 100644 index 30b63429521..00000000000 --- a/build/lib/eslint/code-translation-remind.js +++ /dev/null @@ -1,57 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -var _a; -const fs_1 = require("fs"); -const utils_1 = require("./utils"); -module.exports = new (_a = class TranslationRemind { - constructor() { - this.meta = { - messages: { - missing: 'Please add \'{{resource}}\' to ./build/lib/i18n.resources.json file to use translations here.' - } - }; - } - create(context) { - return (0, utils_1.createImportRuleListener)((node, path) => this._checkImport(context, node, path)); - } - _checkImport(context, node, path) { - if (path !== TranslationRemind.NLS_MODULE) { - return; - } - const currentFile = context.getFilename(); - const matchService = currentFile.match(/vs\/workbench\/services\/\w+/); - const matchPart = currentFile.match(/vs\/workbench\/contrib\/\w+/); - if (!matchService && !matchPart) { - return; - } - const resource = matchService ? matchService[0] : matchPart[0]; - let resourceDefined = false; - let json; - try { - json = (0, fs_1.readFileSync)('./build/lib/i18n.resources.json', 'utf8'); - } - catch (e) { - console.error('[translation-remind rule]: File with resources to pull from Transifex was not found. Aborting translation resource check for newly defined workbench part/service.'); - return; - } - const workbenchResources = JSON.parse(json).workbench; - workbenchResources.forEach((existingResource) => { - if (existingResource.name === resource) { - resourceDefined = true; - return; - } - }); - if (!resourceDefined) { - context.report({ - loc: node.loc, - messageId: 'missing', - data: { resource } - }); - } - } - }, - _a.NLS_MODULE = 'vs/nls', - _a); diff --git a/build/lib/eslint/utils.js b/build/lib/eslint/utils.js deleted file mode 100644 index c58e4e24be1..00000000000 --- a/build/lib/eslint/utils.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createImportRuleListener = void 0; -function createImportRuleListener(validateImport) { - function _checkImport(node) { - if (node && node.type === 'Literal' && typeof node.value === 'string') { - validateImport(node, node.value); - } - } - return { - // import ??? from 'module' - ImportDeclaration: (node) => { - _checkImport(node.source); - }, - // import('module').then(...) OR await import('module') - ['CallExpression[callee.type="Import"][arguments.length=1] > Literal']: (node) => { - _checkImport(node); - }, - // import foo = ... - ['TSImportEqualsDeclaration > TSExternalModuleReference > Literal']: (node) => { - _checkImport(node); - }, - // export ?? from 'module' - ExportAllDeclaration: (node) => { - _checkImport(node.source); - }, - // export {foo} from 'module' - ExportNamedDeclaration: (node) => { - _checkImport(node.source); - }, - }; -} -exports.createImportRuleListener = createImportRuleListener; diff --git a/build/lib/eslint/vscode-dts-cancellation.js b/build/lib/eslint/vscode-dts-cancellation.js deleted file mode 100644 index 65b9e4c1fe1..00000000000 --- a/build/lib/eslint/vscode-dts-cancellation.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -const experimental_utils_1 = require("@typescript-eslint/experimental-utils"); -module.exports = new class ApiProviderNaming { - constructor() { - this.meta = { - messages: { - noToken: 'Function lacks a cancellation token, preferable as last argument', - } - }; - } - create(context) { - return { - ['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature[key.name=/^(provide|resolve).+/]']: (node) => { - let found = false; - for (const param of node.params) { - if (param.type === experimental_utils_1.AST_NODE_TYPES.Identifier) { - found = found || param.name === 'token'; - } - } - if (!found) { - context.report({ - node, - messageId: 'noToken' - }); - } - } - }; - } -}; diff --git a/build/lib/eslint/vscode-dts-create-func.js b/build/lib/eslint/vscode-dts-create-func.js deleted file mode 100644 index e9ec659cef1..00000000000 --- a/build/lib/eslint/vscode-dts-create-func.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -const experimental_utils_1 = require("@typescript-eslint/experimental-utils"); -module.exports = new class ApiLiteralOrTypes { - constructor() { - this.meta = { - docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#creating-objects' }, - messages: { sync: '`createXYZ`-functions are constructor-replacements and therefore must return sync', } - }; - } - create(context) { - return { - ['TSDeclareFunction Identifier[name=/create.*/]']: (node) => { - const decl = node.parent; - if (decl.returnType?.typeAnnotation.type !== experimental_utils_1.AST_NODE_TYPES.TSTypeReference) { - return; - } - if (decl.returnType.typeAnnotation.typeName.type !== experimental_utils_1.AST_NODE_TYPES.Identifier) { - return; - } - const ident = decl.returnType.typeAnnotation.typeName.name; - if (ident === 'Promise' || ident === 'Thenable') { - context.report({ - node, - messageId: 'sync' - }); - } - } - }; - } -}; diff --git a/build/lib/eslint/vscode-dts-event-naming.js b/build/lib/eslint/vscode-dts-event-naming.js deleted file mode 100644 index 1e376cca734..00000000000 --- a/build/lib/eslint/vscode-dts-event-naming.js +++ /dev/null @@ -1,86 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -var _a; -const experimental_utils_1 = require("@typescript-eslint/experimental-utils"); -module.exports = new (_a = class ApiEventNaming { - constructor() { - this.meta = { - docs: { - url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#event-naming' - }, - messages: { - naming: 'Event names must follow this patten: `on[Did|Will]`', - verb: 'Unknown verb \'{{verb}}\' - is this really a verb? Iff so, then add this verb to the configuration', - subject: 'Unknown subject \'{{subject}}\' - This subject has not been used before but it should refer to something in the API', - unknown: 'UNKNOWN event declaration, lint-rule needs tweaking' - } - }; - } - create(context) { - const config = context.options[0]; - const allowed = new Set(config.allowed); - const verbs = new Set(config.verbs); - return { - ['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node) => { - const def = node.parent?.parent?.parent; - const ident = this.getIdent(def); - if (!ident) { - // event on unknown structure... - return context.report({ - node, - message: 'unknown' - }); - } - if (allowed.has(ident.name)) { - // configured exception - return; - } - const match = ApiEventNaming._nameRegExp.exec(ident.name); - if (!match) { - context.report({ - node: ident, - messageId: 'naming' - }); - return; - } - // check that is spelled out (configured) as verb - if (!verbs.has(match[2].toLowerCase())) { - context.report({ - node: ident, - messageId: 'verb', - data: { verb: match[2] } - }); - } - // check that a subject (if present) has occurred - if (match[3]) { - const regex = new RegExp(match[3], 'ig'); - const parts = context.getSourceCode().getText().split(regex); - if (parts.length < 3) { - context.report({ - node: ident, - messageId: 'subject', - data: { subject: match[3] } - }); - } - } - } - }; - } - getIdent(def) { - if (!def) { - return; - } - if (def.type === experimental_utils_1.AST_NODE_TYPES.Identifier) { - return def; - } - else if ((def.type === experimental_utils_1.AST_NODE_TYPES.TSPropertySignature || def.type === experimental_utils_1.AST_NODE_TYPES.Property) && def.key.type === experimental_utils_1.AST_NODE_TYPES.Identifier) { - return def.key; - } - return this.getIdent(def.parent); - } - }, - _a._nameRegExp = /on(Did|Will)([A-Z][a-z]+)([A-Z][a-z]+)?/, - _a); diff --git a/build/lib/eslint/vscode-dts-interface-naming.js b/build/lib/eslint/vscode-dts-interface-naming.js deleted file mode 100644 index 70ca810825b..00000000000 --- a/build/lib/eslint/vscode-dts-interface-naming.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -var _a; -module.exports = new (_a = class ApiInterfaceNaming { - constructor() { - this.meta = { - messages: { - naming: 'Interfaces must not be prefixed with uppercase `I`', - } - }; - } - create(context) { - return { - ['TSInterfaceDeclaration Identifier']: (node) => { - const name = node.name; - if (ApiInterfaceNaming._nameRegExp.test(name)) { - context.report({ - node, - messageId: 'naming' - }); - } - } - }; - } - }, - _a._nameRegExp = /I[A-Z]/, - _a); diff --git a/build/lib/eslint/vscode-dts-literal-or-types.js b/build/lib/eslint/vscode-dts-literal-or-types.js deleted file mode 100644 index e4c075db91c..00000000000 --- a/build/lib/eslint/vscode-dts-literal-or-types.js +++ /dev/null @@ -1,25 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -module.exports = new class ApiLiteralOrTypes { - constructor() { - this.meta = { - docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#enums' }, - messages: { useEnum: 'Use enums, not literal-or-types', } - }; - } - create(context) { - return { - ['TSTypeAnnotation TSUnionType']: (node) => { - if (node.types.every(value => value.type === 'TSLiteralType')) { - context.report({ - node: node, - messageId: 'useEnum' - }); - } - } - }; - } -}; diff --git a/build/lib/eslint/vscode-dts-provider-naming.js b/build/lib/eslint/vscode-dts-provider-naming.js deleted file mode 100644 index 0d94a8a9223..00000000000 --- a/build/lib/eslint/vscode-dts-provider-naming.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -var _a; -module.exports = new (_a = class ApiProviderNaming { - constructor() { - this.meta = { - messages: { - naming: 'A provider should only have functions like provideXYZ or resolveXYZ', - } - }; - } - create(context) { - const config = context.options[0]; - const allowed = new Set(config.allowed); - return { - ['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature']: (node) => { - const interfaceName = node.parent?.parent.id.name; - if (allowed.has(interfaceName)) { - // allowed - return; - } - const methodName = node.key.name; - if (!ApiProviderNaming._providerFunctionNames.test(methodName)) { - context.report({ - node, - messageId: 'naming' - }); - } - } - }; - } - }, - _a._providerFunctionNames = /^(provide|resolve|prepare).+/, - _a); diff --git a/build/lib/eslint/vscode-dts-region-comments.js b/build/lib/eslint/vscode-dts-region-comments.js deleted file mode 100644 index 2dc9487314e..00000000000 --- a/build/lib/eslint/vscode-dts-region-comments.js +++ /dev/null @@ -1,35 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -module.exports = new class ApiEventNaming { - constructor() { - this.meta = { - messages: { - comment: 'region comments should start with a camel case identifier, `:`, then either a GH issue link or owner, e.g #region myProposalName: https://github.com/microsoft/vscode/issues/', - } - }; - } - create(context) { - const sourceCode = context.getSourceCode(); - return { - ['Program']: (_node) => { - for (const comment of sourceCode.getAllComments()) { - if (comment.type !== 'Line') { - continue; - } - if (!/^\s*#region /.test(comment.value)) { - continue; - } - if (!/^\s*#region ([a-z]+): (@[a-z]+|https:\/\/github.com\/microsoft\/vscode\/issues\/\d+)/i.test(comment.value)) { - context.report({ - node: comment, - messageId: 'comment', - }); - } - } - } - }; - } -}; diff --git a/build/lib/eslint/vscode-dts-use-thenable.js b/build/lib/eslint/vscode-dts-use-thenable.js deleted file mode 100644 index 7e23953cb69..00000000000 --- a/build/lib/eslint/vscode-dts-use-thenable.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -module.exports = new class ApiEventNaming { - constructor() { - this.meta = { - messages: { - usage: 'Use the Thenable-type instead of the Promise type', - } - }; - } - create(context) { - return { - ['TSTypeAnnotation TSTypeReference Identifier[name="Promise"]']: (node) => { - context.report({ - node, - messageId: 'usage', - }); - } - }; - } -}; diff --git a/build/lib/eslint/vscode-dts-vscode-in-comments.js b/build/lib/eslint/vscode-dts-vscode-in-comments.js deleted file mode 100644 index 8f9a13fb01f..00000000000 --- a/build/lib/eslint/vscode-dts-vscode-in-comments.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -module.exports = new class ApiVsCodeInComments { - constructor() { - this.meta = { - messages: { - comment: `Don't use the term 'vs code' in comments` - } - }; - } - create(context) { - const sourceCode = context.getSourceCode(); - return { - ['Program']: (_node) => { - for (const comment of sourceCode.getAllComments()) { - if (comment.type !== 'Block') { - continue; - } - if (!comment.range) { - continue; - } - const startIndex = comment.range[0] + '/*'.length; - const re = /vs code/ig; - let match; - while ((match = re.exec(comment.value))) { - // Allow using 'VS Code' in quotes - if (comment.value[match.index - 1] === `'` && comment.value[match.index + match[0].length] === `'`) { - continue; - } - // Types for eslint seem incorrect - const start = sourceCode.getLocFromIndex(startIndex + match.index); - const end = sourceCode.getLocFromIndex(startIndex + match.index + match[0].length); - context.report({ - messageId: 'comment', - loc: { start, end } - }); - } - } - } - }; - } -}; diff --git a/build/lib/extensions.js b/build/lib/extensions.js index 168cf8a5d00..a13c5686b7d 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -25,6 +25,7 @@ const buffer = require('gulp-buffer'); const jsoncParser = require("jsonc-parser"); const dependencies_1 = require("./dependencies"); const _ = require("underscore"); +const builtInExtensions_1 = require("./builtInExtensions"); const util = require('./util'); const root = path.dirname(path.dirname(__dirname)); const commit = util.getVersion(root); @@ -312,16 +313,15 @@ function packageLocalExtensionsStream(forWeb) { .pipe(util2.setExecutableBit(['**/*.sh']))); } exports.packageLocalExtensionsStream = packageLocalExtensionsStream; -function packageMarketplaceExtensionsStream(forWeb, galleryServiceUrl) { +function packageMarketplaceExtensionsStream(forWeb) { const marketplaceExtensionsDescriptions = [ ...builtInExtensions.filter(({ name }) => (forWeb ? !marketplaceWebExtensionsExclude.has(name) : true)), ...(forWeb ? webBuiltInExtensions : []) ]; const marketplaceExtensionsStream = minifyExtensionResources(es.merge(...marketplaceExtensionsDescriptions .map(extension => { - const input = (galleryServiceUrl ? fromMarketplace(galleryServiceUrl, extension) : fromGithub(extension)) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - return updateExtensionPackageJSON(input, (data) => { + const src = (0, builtInExtensions_1.getExtensionStream)(extension).pipe(rename(p => p.dirname = `extensions/${p.dirname}`)); + return updateExtensionPackageJSON(src, (data) => { delete data.scripts; delete data.dependencies; delete data.devDependencies; @@ -351,12 +351,20 @@ function scanBuiltinExtensions(extensionsRoot, exclude = []) { const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); const packageNLSPath = children.filter(child => child === 'package.nls.json')[0]; const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined; + let browserNlsMetadataPath; + if (packageJSON.browser) { + const browserEntrypointFolderPath = path.join(extensionFolder, path.dirname(packageJSON.browser)); + if (fs.existsSync(path.join(extensionsRoot, browserEntrypointFolderPath, 'nls.metadata.json'))) { + browserNlsMetadataPath = path.join(browserEntrypointFolderPath, 'nls.metadata.json'); + } + } const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; scannedExtensions.push({ extensionPath: extensionFolder, packageJSON, packageNLS, + browserNlsMetadataPath, readmePath: readme ? path.join(extensionFolder, readme) : undefined, changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, }); @@ -399,6 +407,7 @@ const esbuildMediaScripts = [ 'markdown-language-features/esbuild-preview.js', 'markdown-math/esbuild.js', 'notebook-renderers/esbuild.js', + 'ipynb/esbuild.js', 'simple-browser/esbuild-preview.js', ]; async function webpackExtensions(taskName, isWatch, webpackConfigLocations) { diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 89aa014a0d6..fdd7d9c3c0d 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -25,6 +25,7 @@ import * as jsoncParser from 'jsonc-parser'; import webpack = require('webpack'); import { getProductionDependencies } from './dependencies'; import _ = require('underscore'); +import { getExtensionStream } from './builtInExtensions'; const util = require('./util'); const root = path.dirname(path.dirname(__dirname)); const commit = util.getVersion(root); @@ -381,7 +382,7 @@ export function packageLocalExtensionsStream(forWeb: boolean): Stream { ); } -export function packageMarketplaceExtensionsStream(forWeb: boolean, galleryServiceUrl?: string): Stream { +export function packageMarketplaceExtensionsStream(forWeb: boolean): Stream { const marketplaceExtensionsDescriptions = [ ...builtInExtensions.filter(({ name }) => (forWeb ? !marketplaceWebExtensionsExclude.has(name) : true)), ...(forWeb ? webBuiltInExtensions : []) @@ -390,9 +391,8 @@ export function packageMarketplaceExtensionsStream(forWeb: boolean, galleryServi es.merge( ...marketplaceExtensionsDescriptions .map(extension => { - const input = (galleryServiceUrl ? fromMarketplace(galleryServiceUrl, extension) : fromGithub(extension)) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - return updateExtensionPackageJSON(input, (data: any) => { + const src = getExtensionStream(extension).pipe(rename(p => p.dirname = `extensions/${p.dirname}`)); + return updateExtensionPackageJSON(src, (data: any) => { delete data.scripts; delete data.dependencies; delete data.devDependencies; @@ -412,6 +412,7 @@ export interface IScannedBuiltinExtension { extensionPath: string; packageJSON: any; packageNLS?: any; + browserNlsMetadataPath?: string; readmePath?: string; changelogPath?: string; } @@ -436,6 +437,13 @@ export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); const packageNLSPath = children.filter(child => child === 'package.nls.json')[0]; const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined; + let browserNlsMetadataPath: string | undefined; + if (packageJSON.browser) { + const browserEntrypointFolderPath = path.join(extensionFolder, path.dirname(packageJSON.browser)); + if (fs.existsSync(path.join(extensionsRoot, browserEntrypointFolderPath, 'nls.metadata.json'))) { + browserNlsMetadataPath = path.join(browserEntrypointFolderPath, 'nls.metadata.json'); + } + } const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; @@ -443,6 +451,7 @@ export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] extensionPath: extensionFolder, packageJSON, packageNLS, + browserNlsMetadataPath, readmePath: readme ? path.join(extensionFolder, readme) : undefined, changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, }); @@ -486,6 +495,7 @@ const esbuildMediaScripts = [ 'markdown-language-features/esbuild-preview.js', 'markdown-math/esbuild.js', 'notebook-renderers/esbuild.js', + 'ipynb/esbuild.js', 'simple-browser/esbuild-preview.js', ]; diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 13de16ce9a0..b97da8b9fbe 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -491,7 +491,7 @@ function processNlsFiles(opts) { }); } exports.processNlsFiles = processNlsFiles; -const editorProject = 'vscode-editor', workbenchProject = 'vscode-workbench', extensionsProject = 'vscode-extensions', setupProject = 'vscode-setup'; +const editorProject = 'vscode-editor', workbenchProject = 'vscode-workbench', extensionsProject = 'vscode-extensions', setupProject = 'vscode-setup', serverProject = 'vscode-server'; function getResource(sourceFile) { let resource; if (/^vs\/platform/.test(sourceFile)) { @@ -509,6 +509,9 @@ function getResource(sourceFile) { else if (/^vs\/code/.test(sourceFile)) { return { name: 'vs/code', project: workbenchProject }; } + else if (/^vs\/server/.test(sourceFile)) { + return { name: 'vs/server', project: serverProject }; + } else if (/^vs\/workbench\/contrib/.test(sourceFile)) { resource = sourceFile.split('/', 4).join('/'); return { name: resource, project: workbenchProject }; diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 9f39f658de2..dd949e618f2 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -279,7 +279,7 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/contrib/sessionSync", + "name": "vs/workbench/contrib/editSessions", "project": "vscode-workbench" }, { @@ -294,6 +294,14 @@ "name": "vs/workbench/contrib/audioCues", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/deprecatedExtensionMigrator", + "project": "vscode-workbench" + }, + { + "name": "vs/workbench/contrib/bracketPairColorizer2Telemetry", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/offline", "project": "vscode-workbench" @@ -431,7 +439,7 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/services/sessionSync", + "name": "vs/workbench/services/editSessions", "project": "vscode-workbench" }, { diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 05b0634120b..20c1dc93f99 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -611,7 +611,8 @@ export function processNlsFiles(opts: { fileHeader: string; languages: Language[ const editorProject: string = 'vscode-editor', workbenchProject: string = 'vscode-workbench', extensionsProject: string = 'vscode-extensions', - setupProject: string = 'vscode-setup'; + setupProject: string = 'vscode-setup', + serverProject: string = 'vscode-server'; export function getResource(sourceFile: string): Resource { let resource: string; @@ -626,6 +627,8 @@ export function getResource(sourceFile: string): Resource { return { name: 'vs/base', project: editorProject }; } else if (/^vs\/code/.test(sourceFile)) { return { name: 'vs/code', project: workbenchProject }; + } else if (/^vs\/server/.test(sourceFile)) { + return { name: 'vs/server', project: serverProject }; } else if (/^vs\/workbench\/contrib/.test(sourceFile)) { resource = sourceFile.split('/', 4).join('/'); return { name: resource, project: workbenchProject }; diff --git a/build/lib/layersChecker.js b/build/lib/layersChecker.js index c83d6fcf984..cbc1f95b979 100644 --- a/build/lib/layersChecker.js +++ b/build/lib/layersChecker.js @@ -51,6 +51,7 @@ const CORE_TYPES = [ 'BigInt64Array', 'btoa', 'atob', + 'AbortController', 'AbortSignal', 'MessageChannel', 'MessagePort', @@ -72,6 +73,11 @@ const RULES = [ target: '**/vs/**/test/**', skip: true // -> skip all test files }, + // TODO@bpasero remove me once electron utility process has landed + { + target: '**/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts', + skip: true + }, // Common: vs/base/common/platform.ts { target: '**/vs/base/common/platform.ts', @@ -223,7 +229,7 @@ function checkFile(program, sourceFile, rule) { } if (rule.disallowedTypes?.some(disallowed => disallowed === text)) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; } @@ -247,7 +253,7 @@ function checkFile(program, sourceFile, rule) { for (const disallowedDefinition of rule.disallowedDefinitions) { if (definitionFileName.indexOf(disallowedDefinition) >= 0) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; } diff --git a/build/lib/layersChecker.ts b/build/lib/layersChecker.ts index 95810c3b5f4..12b900162aa 100644 --- a/build/lib/layersChecker.ts +++ b/build/lib/layersChecker.ts @@ -52,6 +52,7 @@ const CORE_TYPES = [ 'BigInt64Array', 'btoa', 'atob', + 'AbortController', 'AbortSignal', 'MessageChannel', 'MessagePort', @@ -77,6 +78,12 @@ const RULES: IRule[] = [ skip: true // -> skip all test files }, + // TODO@bpasero remove me once electron utility process has landed + { + target: '**/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts', + skip: true + }, + // Common: vs/base/common/platform.ts { target: '**/vs/base/common/platform.ts', @@ -262,7 +269,7 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) if (rule.disallowedTypes?.some(disallowed => disallowed === text)) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; @@ -289,7 +296,7 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) if (definitionFileName.indexOf(disallowedDefinition) >= 0) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; diff --git a/build/lib/policies.js b/build/lib/policies.js index 3e2a10df350..2fe3339ccea 100644 --- a/build/lib/policies.js +++ b/build/lib/policies.js @@ -13,6 +13,7 @@ const Parser = require("tree-sitter"); const node_fetch_1 = require("node-fetch"); const { typescript } = require('tree-sitter-typescript'); const product = require('../../product.json'); +const packageJson = require('../../package.json'); function isNlsString(value) { return value ? typeof value !== 'string' : false; } @@ -408,23 +409,63 @@ const Languages = { 'tr': 'tr-tr', 'pl': 'pl-pl', }; -async function getLatestStableVersion(updateUrl) { - const res = await (0, node_fetch_1.default)(`${updateUrl}/api/update/darwin/stable/latest`); - const { name: version } = await res.json(); - return version; -} -async function getNLS(resourceUrlTemplate, languageId, version) { +async function getSpecificNLS(resourceUrlTemplate, languageId, version) { const resource = { publisher: 'ms-ceintl', name: `vscode-language-pack-${languageId}`, - version, + version: `${version[0]}.${version[1]}.${version[2]}`, path: 'extension/translations/main.i18n.json' }; const url = resourceUrlTemplate.replace(/\{([^}]+)\}/g, (_, key) => resource[key]); const res = await (0, node_fetch_1.default)(url); + if (res.status !== 200) { + throw new Error(`[${res.status}] Error downloading language pack ${languageId}@${version}`); + } const { contents: result } = await res.json(); return result; } +function parseVersion(version) { + const [, major, minor, patch] = /^(\d+)\.(\d+)\.(\d+)/.exec(version); + return [parseInt(major), parseInt(minor), parseInt(patch)]; +} +function compareVersions(a, b) { + if (a[0] !== b[0]) { + return a[0] - b[0]; + } + if (a[1] !== b[1]) { + return a[1] - b[1]; + } + return a[2] - b[2]; +} +async function queryVersions(serviceUrl, languageId) { + const res = await (0, node_fetch_1.default)(`${serviceUrl}/extensionquery`, { + method: 'POST', + headers: { + 'Accept': 'application/json;api-version=3.0-preview.1', + 'Content-Type': 'application/json', + 'User-Agent': 'VS Code Build', + }, + body: JSON.stringify({ + filters: [{ criteria: [{ filterType: 7, value: `ms-ceintl.vscode-language-pack-${languageId}` }] }], + flags: 0x1 + }) + }); + if (res.status !== 200) { + throw new Error(`[${res.status}] Error querying for extension: ${languageId}`); + } + const result = await res.json(); + return result.results[0].extensions[0].versions.map(v => parseVersion(v.version)).sort(compareVersions); +} +async function getNLS(extensionGalleryServiceUrl, resourceUrlTemplate, languageId, version) { + const versions = await queryVersions(extensionGalleryServiceUrl, languageId); + const nextMinor = [version[0], version[1] + 1, 0]; + const compatibleVersions = versions.filter(v => compareVersions(v, nextMinor) < 0); + const latestCompatibleVersion = compatibleVersions.at(-1); // order is newest to oldest + if (!latestCompatibleVersion) { + throw new Error(`No compatible language pack found for ${languageId} for version ${version}`); + } + return await getSpecificNLS(resourceUrlTemplate, languageId, latestCompatibleVersion); +} async function parsePolicies() { const parser = new Parser(); parser.setLanguage(typescript); @@ -440,9 +481,9 @@ async function parsePolicies() { return policies; } async function getTranslations() { - const updateUrl = product.updateUrl; - if (!updateUrl) { - console.warn(`Skipping policy localization: No 'updateUrl' found in 'product.json'.`); + const extensionGalleryServiceUrl = product.extensionsGallery?.serviceUrl; + if (!extensionGalleryServiceUrl) { + console.warn(`Skipping policy localization: No 'extensionGallery.serviceUrl' found in 'product.json'.`); return []; } const resourceUrlTemplate = product.extensionsGallery?.resourceUrlTemplate; @@ -450,9 +491,9 @@ async function getTranslations() { console.warn(`Skipping policy localization: No 'resourceUrlTemplate' found in 'product.json'.`); return []; } - const version = await getLatestStableVersion(updateUrl); + const version = parseVersion(packageJson.version); const languageIds = Object.keys(Languages); - return await Promise.all(languageIds.map(languageId => getNLS(resourceUrlTemplate, languageId, version) + return await Promise.all(languageIds.map(languageId => getNLS(extensionGalleryServiceUrl, resourceUrlTemplate, languageId, version) .then(languageTranslations => ({ languageId, languageTranslations })))); } async function main() { diff --git a/build/lib/policies.ts b/build/lib/policies.ts index 62ea4d561e5..0e89508fe8e 100644 --- a/build/lib/policies.ts +++ b/build/lib/policies.ts @@ -12,6 +12,7 @@ import * as Parser from 'tree-sitter'; import fetch from 'node-fetch'; const { typescript } = require('tree-sitter-typescript'); const product = require('../../product.json'); +const packageJson = require('../../package.json'); type NlsString = { value: string; nlsKey: string }; @@ -587,26 +588,73 @@ const Languages = { type LanguageTranslations = { [moduleName: string]: { [nlsKey: string]: string } }; type Translations = { languageId: string; languageTranslations: LanguageTranslations }[]; -async function getLatestStableVersion(updateUrl: string) { - const res = await fetch(`${updateUrl}/api/update/darwin/stable/latest`); - const { name: version } = await res.json() as { name: string }; - return version; -} +type Version = [number, number, number]; -async function getNLS(resourceUrlTemplate: string, languageId: string, version: string) { +async function getSpecificNLS(resourceUrlTemplate: string, languageId: string, version: Version) { const resource = { publisher: 'ms-ceintl', name: `vscode-language-pack-${languageId}`, - version, + version: `${version[0]}.${version[1]}.${version[2]}`, path: 'extension/translations/main.i18n.json' }; const url = resourceUrlTemplate.replace(/\{([^}]+)\}/g, (_, key) => resource[key as keyof typeof resource]); const res = await fetch(url); + + if (res.status !== 200) { + throw new Error(`[${res.status}] Error downloading language pack ${languageId}@${version}`); + } + const { contents: result } = await res.json() as { contents: LanguageTranslations }; return result; } +function parseVersion(version: string): Version { + const [, major, minor, patch] = /^(\d+)\.(\d+)\.(\d+)/.exec(version)!; + return [parseInt(major), parseInt(minor), parseInt(patch)]; +} + +function compareVersions(a: Version, b: Version): number { + if (a[0] !== b[0]) { return a[0] - b[0]; } + if (a[1] !== b[1]) { return a[1] - b[1]; } + return a[2] - b[2]; +} + +async function queryVersions(serviceUrl: string, languageId: string): Promise { + const res = await fetch(`${serviceUrl}/extensionquery`, { + method: 'POST', + headers: { + 'Accept': 'application/json;api-version=3.0-preview.1', + 'Content-Type': 'application/json', + 'User-Agent': 'VS Code Build', + }, + body: JSON.stringify({ + filters: [{ criteria: [{ filterType: 7, value: `ms-ceintl.vscode-language-pack-${languageId}` }] }], + flags: 0x1 + }) + }); + + if (res.status !== 200) { + throw new Error(`[${res.status}] Error querying for extension: ${languageId}`); + } + + const result = await res.json() as { results: [{ extensions: { versions: { version: string }[] }[] }] }; + return result.results[0].extensions[0].versions.map(v => parseVersion(v.version)).sort(compareVersions); +} + +async function getNLS(extensionGalleryServiceUrl: string, resourceUrlTemplate: string, languageId: string, version: Version) { + const versions = await queryVersions(extensionGalleryServiceUrl, languageId); + const nextMinor: Version = [version[0], version[1] + 1, 0]; + const compatibleVersions = versions.filter(v => compareVersions(v, nextMinor) < 0); + const latestCompatibleVersion = compatibleVersions.at(-1)!; // order is newest to oldest + + if (!latestCompatibleVersion) { + throw new Error(`No compatible language pack found for ${languageId} for version ${version}`); + } + + return await getSpecificNLS(resourceUrlTemplate, languageId, latestCompatibleVersion); +} + async function parsePolicies(): Promise { const parser = new Parser(); parser.setLanguage(typescript); @@ -626,10 +674,10 @@ async function parsePolicies(): Promise { } async function getTranslations(): Promise { - const updateUrl = product.updateUrl; + const extensionGalleryServiceUrl = product.extensionsGallery?.serviceUrl; - if (!updateUrl) { - console.warn(`Skipping policy localization: No 'updateUrl' found in 'product.json'.`); + if (!extensionGalleryServiceUrl) { + console.warn(`Skipping policy localization: No 'extensionGallery.serviceUrl' found in 'product.json'.`); return []; } @@ -640,11 +688,11 @@ async function getTranslations(): Promise { return []; } - const version = await getLatestStableVersion(updateUrl); + const version = parseVersion(packageJson.version); const languageIds = Object.keys(Languages); return await Promise.all(languageIds.map( - languageId => getNLS(resourceUrlTemplate, languageId, version) + languageId => getNLS(extensionGalleryServiceUrl, resourceUrlTemplate, languageId, version) .then(languageTranslations => ({ languageId, languageTranslations })) )); } diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index 8fc5930c024..ff18694436d 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -89,6 +89,8 @@ function discoverAndReadFiles(ts, options) { const in_queue = Object.create(null); const queue = []; const enqueue = (moduleId) => { + // To make the treeshaker work on windows... + moduleId = moduleId.replace(/\\/g, '/'); if (in_queue[moduleId]) { return; } @@ -226,6 +228,12 @@ function getColor(node) { function setColor(node, color) { node.$$$color = color; } +function markNeededSourceFile(node) { + node.$$$neededSourceFile = true; +} +function isNeededSourceFile(node) { + return Boolean(node.$$$neededSourceFile); +} function nodeOrParentIsBlack(node) { while (node) { const color = getColor(node); @@ -351,6 +359,19 @@ function markNodes(ts, languageService, options) { } }); } + /** + * Return the parent of `node` which is an ImportDeclaration + */ + function findParentImportDeclaration(node) { + let _node = node; + do { + if (ts.isImportDeclaration(_node)) { + return _node; + } + _node = _node.parent; + } while (_node); + return null; + } function enqueue_gray(node) { if (nodeOrParentIsBlack(node) || getColor(node) === 1 /* NodeColor.Gray */) { return; @@ -418,6 +439,8 @@ function markNodes(ts, languageService, options) { console.warn(`Cannot find source file ${filename}`); return; } + // This source file should survive even if it is empty + markNeededSourceFile(sourceFile); enqueue_black(sourceFile); } function enqueueImport(node, importText) { @@ -470,6 +493,10 @@ function markNodes(ts, languageService, options) { const [symbol, symbolImportNode] = getRealNodeSymbol(ts, checker, node); if (symbolImportNode) { setColor(symbolImportNode, 2 /* NodeColor.Black */); + const importDeclarationNode = findParentImportDeclaration(symbolImportNode); + if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) { + enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text); + } } if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { for (let i = 0, len = symbol.declarations.length; i < len; i++) { @@ -661,11 +688,23 @@ function generateResult(ts, languageService, shakeLevel) { } if (getColor(sourceFile) !== 2 /* NodeColor.Black */) { if (!nodeOrChildIsBlack(sourceFile)) { - // none of the elements are reachable => don't write this file at all! - return; + // none of the elements are reachable + if (isNeededSourceFile(sourceFile)) { + // this source file must be written, even if nothing is used from it + // because there is an import somewhere for it. + // However, TS complains with empty files with the error "x" is not a module, + // so we will export a dummy variable + result = 'export const __dummy = 0;'; + } + else { + // don't write this file at all! + return; + } + } + else { + sourceFile.forEachChild(writeMarkedNodes); + result += sourceFile.endOfFileToken.getFullText(sourceFile); } - sourceFile.forEachChild(writeMarkedNodes); - result += sourceFile.endOfFileToken.getFullText(sourceFile); } else { result = text; diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index 1d2e1bd4381..ef829426d94 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -142,6 +142,8 @@ function discoverAndReadFiles(ts: typeof import('typescript'), options: ITreeSha const queue: string[] = []; const enqueue = (moduleId: string) => { + // To make the treeshaker work on windows... + moduleId = moduleId.replace(/\\/g, '/'); if (in_queue[moduleId]) { return; } @@ -305,6 +307,12 @@ function getColor(node: ts.Node): NodeColor { function setColor(node: ts.Node, color: NodeColor): void { (node).$$$color = color; } +function markNeededSourceFile(node: ts.SourceFile): void { + (node).$$$neededSourceFile = true; +} +function isNeededSourceFile(node: ts.SourceFile): boolean { + return Boolean((node).$$$neededSourceFile); +} function nodeOrParentIsBlack(node: ts.Node): boolean { while (node) { const color = getColor(node); @@ -447,6 +455,20 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language }); } + /** + * Return the parent of `node` which is an ImportDeclaration + */ + function findParentImportDeclaration(node: ts.Declaration): ts.ImportDeclaration | null { + let _node: ts.Node = node; + do { + if (ts.isImportDeclaration(_node)) { + return _node; + } + _node = _node.parent; + } while (_node); + return null; + } + function enqueue_gray(node: ts.Node): void { if (nodeOrParentIsBlack(node) || getColor(node) === NodeColor.Gray) { return; @@ -529,6 +551,8 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language console.warn(`Cannot find source file ${filename}`); return; } + // This source file should survive even if it is empty + markNeededSourceFile(sourceFile); enqueue_black(sourceFile); } @@ -588,6 +612,10 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language const [symbol, symbolImportNode] = getRealNodeSymbol(ts, checker, node); if (symbolImportNode) { setColor(symbolImportNode, NodeColor.Black); + const importDeclarationNode = findParentImportDeclaration(symbolImportNode); + if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) { + enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text); + } } if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { @@ -800,11 +828,21 @@ function generateResult(ts: typeof import('typescript'), languageService: ts.Lan if (getColor(sourceFile) !== NodeColor.Black) { if (!nodeOrChildIsBlack(sourceFile)) { - // none of the elements are reachable => don't write this file at all! - return; + // none of the elements are reachable + if (isNeededSourceFile(sourceFile)) { + // this source file must be written, even if nothing is used from it + // because there is an import somewhere for it. + // However, TS complains with empty files with the error "x" is not a module, + // so we will export a dummy variable + result = 'export const __dummy = 0;'; + } else { + // don't write this file at all! + return; + } + } else { + sourceFile.forEachChild(writeMarkedNodes); + result += sourceFile.endOfFileToken.getFullText(sourceFile); } - sourceFile.forEachChild(writeMarkedNodes); - result += sourceFile.endOfFileToken.getFullText(sourceFile); } else { result = text; } diff --git a/build/lib/tsb/index.js b/build/lib/tsb/index.js index a0b6423bb61..51806a479ea 100644 --- a/build/lib/tsb/index.js +++ b/build/lib/tsb/index.js @@ -92,7 +92,9 @@ function create(projectPath, existingOptions, config, onError = _defaultOnError) } let result; if (config.transpileOnly) { - const transpiler = new transpiler_1.Transpiler(logFn, printDiagnostic, projectPath, cmdLine); + const transpiler = !config.transpileWithSwc + ? new transpiler_1.TscTranspiler(logFn, printDiagnostic, projectPath, cmdLine) + : new transpiler_1.SwcTranspiler(logFn, printDiagnostic, projectPath, cmdLine); result = (() => createTranspileStream(transpiler)); } else { diff --git a/build/lib/tsb/index.ts b/build/lib/tsb/index.ts index 384a6beeb93..0c5952cec34 100644 --- a/build/lib/tsb/index.ts +++ b/build/lib/tsb/index.ts @@ -13,7 +13,7 @@ import { strings } from './utils'; import { readFileSync, statSync } from 'fs'; import * as log from 'fancy-log'; import colors = require('ansi-colors'); -import { Transpiler } from './transpiler'; +import { ITranspiler, SwcTranspiler, TscTranspiler } from './transpiler'; export interface IncrementalCompiler { (token?: any): Readable & Writable; @@ -36,7 +36,7 @@ const _defaultOnError = (err: string) => console.log(JSON.stringify(err, null, 4 export function create( projectPath: string, existingOptions: Partial, - config: { verbose?: boolean; transpileOnly?: boolean; transpileOnlyIncludesDts?: boolean }, + config: { verbose?: boolean; transpileOnly?: boolean; transpileOnlyIncludesDts?: boolean; transpileWithSwc?: boolean }, onError: (message: string) => void = _defaultOnError ): IncrementalCompiler { @@ -95,7 +95,7 @@ export function create( } // TRANSPILE ONLY stream doing just TS to JS conversion - function createTranspileStream(transpiler: Transpiler): Readable & Writable { + function createTranspileStream(transpiler: ITranspiler): Readable & Writable { return through(function (this: through.ThroughStream & { queue(a: any): void }, file: Vinyl) { // give the file to the compiler if (file.isStream()) { @@ -126,7 +126,9 @@ export function create( let result: IncrementalCompiler; if (config.transpileOnly) { - const transpiler = new Transpiler(logFn, printDiagnostic, projectPath, cmdLine); + const transpiler = !config.transpileWithSwc + ? new TscTranspiler(logFn, printDiagnostic, projectPath, cmdLine) + : new SwcTranspiler(logFn, printDiagnostic, projectPath, cmdLine); result = (() => createTranspileStream(transpiler)); } else { const _builder = builder.createTypeScriptBuilder({ logFn }, projectPath, cmdLine); diff --git a/build/lib/tsb/transpiler.js b/build/lib/tsb/transpiler.js index 38e6b5c00e4..e5e90128d09 100644 --- a/build/lib/tsb/transpiler.js +++ b/build/lib/tsb/transpiler.js @@ -3,8 +3,10 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +var _a; Object.defineProperty(exports, "__esModule", { value: true }); -exports.Transpiler = void 0; +exports.SwcTranspiler = exports.TscTranspiler = void 0; +const swc = require("@swc/core"); const ts = require("typescript"); const threads = require("node:worker_threads"); const Vinyl = require("vinyl"); @@ -36,6 +38,35 @@ if (!threads.isMainThread) { threads.parentPort.postMessage(res); }); } +class OutputFileNameOracle { + constructor(cmdLine, configFilePath) { + this.getOutputFileName = (file) => { + try { + // windows: path-sep normalizing + file = ts.normalizePath(file); + if (!cmdLine.options.configFilePath) { + // this is needed for the INTERNAL getOutputFileNames-call below... + cmdLine.options.configFilePath = configFilePath; + } + const isDts = file.endsWith('.d.ts'); + if (isDts) { + file = file.slice(0, -5) + '.ts'; + cmdLine.fileNames.push(file); + } + const outfile = ts.getOutputFileNames(cmdLine, file, true)[0]; + if (isDts) { + cmdLine.fileNames.pop(); + } + return outfile; + } + catch (err) { + console.error(file, cmdLine.fileNames); + console.error(err); + throw new err; + } + }; + } +} class TranspileWorker { constructor(outFileFn) { this.id = TranspileWorker.pool++; @@ -112,39 +143,15 @@ class TranspileWorker { } } TranspileWorker.pool = 1; -class Transpiler { +class TscTranspiler { constructor(logFn, _onError, configFilePath, _cmdLine) { this._onError = _onError; this._cmdLine = _cmdLine; this._workerPool = []; this._queue = []; this._allJobs = []; - logFn('Transpile', `will use ${Transpiler.P} transpile worker`); - this._getOutputFileName = (file) => { - try { - // windows: path-sep normalizing - file = ts.normalizePath(file); - if (!_cmdLine.options.configFilePath) { - // this is needed for the INTERNAL getOutputFileNames-call below... - _cmdLine.options.configFilePath = configFilePath; - } - const isDts = file.endsWith('.d.ts'); - if (isDts) { - file = file.slice(0, -5) + '.ts'; - _cmdLine.fileNames.push(file); - } - const outfile = ts.getOutputFileNames(_cmdLine, file, true)[0]; - if (isDts) { - _cmdLine.fileNames.pop(); - } - return outfile; - } - catch (err) { - console.error(file, _cmdLine.fileNames); - console.error(err); - throw new err; - } - }; + logFn('Transpile', `will use ${TscTranspiler.P} transpile worker`); + this._outputFileNames = new OutputFileNameOracle(_cmdLine, configFilePath); } async join() { // wait for all penindg jobs @@ -161,7 +168,7 @@ class Transpiler { return; } const newLen = this._queue.push(file); - if (newLen > Transpiler.P ** 2) { + if (newLen > TscTranspiler.P ** 2) { this._consumeQueue(); } } @@ -172,8 +179,8 @@ class Transpiler { } // kinda LAZYily create workers if (this._workerPool.length === 0) { - for (let i = 0; i < Transpiler.P; i++) { - this._workerPool.push(new TranspileWorker(file => this._getOutputFileName(file))); + for (let i = 0; i < TscTranspiler.P; i++) { + this._workerPool.push(new TranspileWorker(file => this._outputFileNames.getOutputFileName(file))); } } const freeWorker = this._workerPool.filter(w => !w.isBusy); @@ -187,7 +194,7 @@ class Transpiler { } const job = new Promise(resolve => { const consume = () => { - const files = this._queue.splice(0, Transpiler.P); + const files = this._queue.splice(0, TscTranspiler.P); if (files.length === 0) { // DONE resolve(undefined); @@ -210,11 +217,98 @@ class Transpiler { } } } -exports.Transpiler = Transpiler; -Transpiler.P = Math.floor((0, node_os_1.cpus)().length * .5); +exports.TscTranspiler = TscTranspiler; +TscTranspiler.P = Math.floor((0, node_os_1.cpus)().length * .5); function _isDefaultEmpty(src) { return src .replace('"use strict";', '') .replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1') .trim().length === 0; } +class SwcTranspiler { + constructor(_logFn, _onError, configFilePath, _cmdLine) { + this._logFn = _logFn; + this._onError = _onError; + this._cmdLine = _cmdLine; + this._jobs = []; + _logFn('Transpile', `will use SWC to transpile source files`); + this._outputFileNames = new OutputFileNameOracle(_cmdLine, configFilePath); + } + async join() { + const jobs = this._jobs.slice(); + this._jobs.length = 0; + await Promise.allSettled(jobs); + } + transpile(file) { + if (this._cmdLine.options.noEmit) { + // not doing ANYTHING here + return; + } + const tsSrc = String(file.contents); + const t1 = Date.now(); + let options = SwcTranspiler._swcrcEsm; + if (this._cmdLine.options.module === ts.ModuleKind.AMD) { + const isAmd = /\n(import|export)/m.test(tsSrc); + if (isAmd) { + options = SwcTranspiler._swcrcAmd; + } + } + else if (this._cmdLine.options.module === ts.ModuleKind.CommonJS) { + options = SwcTranspiler._swcrcCommonJS; + } + this._jobs.push(swc.transform(tsSrc, options).then(output => { + // check if output of a DTS-files isn't just "empty" and iff so + // skip this file + if (file.path.endsWith('.d.ts') && _isDefaultEmpty(output.code)) { + return; + } + const outBase = this._cmdLine.options.outDir ?? file.base; + const outPath = this._outputFileNames.getOutputFileName(file.path); + this.onOutfile(new Vinyl({ + path: outPath, + base: outBase, + contents: Buffer.from(output.code), + })); + this._logFn('Transpile', `swc took ${Date.now() - t1}ms for ${file.path}`); + }).catch(err => { + this._onError(err); + })); + } +} +exports.SwcTranspiler = SwcTranspiler; +_a = SwcTranspiler; +// --- .swcrc +SwcTranspiler._swcrcAmd = { + exclude: '\.js$', + jsc: { + parser: { + syntax: 'typescript', + tsx: false, + decorators: true + }, + target: 'es2020', + loose: false, + minify: { + compress: false, + mangle: false + } + }, + module: { + type: 'amd', + noInterop: true + }, + minify: false, +}; +SwcTranspiler._swcrcCommonJS = { + ..._a._swcrcAmd, + module: { + type: 'commonjs', + importInterop: 'none' + } +}; +SwcTranspiler._swcrcEsm = { + ..._a._swcrcAmd, + module: { + type: 'es6' + } +}; diff --git a/build/lib/tsb/transpiler.ts b/build/lib/tsb/transpiler.ts index 7bd789ef6eb..a82cbaef890 100644 --- a/build/lib/tsb/transpiler.ts +++ b/build/lib/tsb/transpiler.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as swc from '@swc/core'; import * as ts from 'typescript'; import * as threads from 'node:worker_threads'; import * as Vinyl from 'vinyl'; @@ -48,6 +49,47 @@ if (!threads.isMainThread) { }); } +class OutputFileNameOracle { + + readonly getOutputFileName: (name: string) => string; + + constructor(cmdLine: ts.ParsedCommandLine, configFilePath: string) { + // very complicated logic to re-use TS internal functions to know the output path + // given a TS input path and its config + type InternalTsApi = typeof ts & { + normalizePath(path: string): string; + getOutputFileNames(commandLine: ts.ParsedCommandLine, inputFileName: string, ignoreCase: boolean): readonly string[]; + }; + this.getOutputFileName = (file) => { + try { + + // windows: path-sep normalizing + file = (ts).normalizePath(file); + + if (!cmdLine.options.configFilePath) { + // this is needed for the INTERNAL getOutputFileNames-call below... + cmdLine.options.configFilePath = configFilePath; + } + const isDts = file.endsWith('.d.ts'); + if (isDts) { + file = file.slice(0, -5) + '.ts'; + cmdLine.fileNames.push(file); + } + const outfile = (ts).getOutputFileNames(cmdLine, file, true)[0]; + if (isDts) { + cmdLine.fileNames.pop(); + } + return outfile; + + } catch (err) { + console.error(file, cmdLine.fileNames); + console.error(err); + throw new err; + } + }; + } +} + class TranspileWorker { private static pool = 1; @@ -141,12 +183,18 @@ class TranspileWorker { } } +export interface ITranspiler { + onOutfile?: (file: Vinyl) => void; + join(): Promise; + transpile(file: Vinyl): void; +} -export class Transpiler { +export class TscTranspiler implements ITranspiler { static P = Math.floor(cpus().length * .5); - private readonly _getOutputFileName: (name: string) => string; + private readonly _outputFileNames: OutputFileNameOracle; + public onOutfile?: (file: Vinyl) => void; @@ -160,42 +208,8 @@ export class Transpiler { configFilePath: string, private readonly _cmdLine: ts.ParsedCommandLine ) { - logFn('Transpile', `will use ${Transpiler.P} transpile worker`); - - - // very complicated logic to re-use TS internal functions to know the output path - // given a TS input path and its config - type InternalTsApi = typeof ts & { - normalizePath(path: string): string; - getOutputFileNames(commandLine: ts.ParsedCommandLine, inputFileName: string, ignoreCase: boolean): readonly string[]; - }; - this._getOutputFileName = (file) => { - try { - - // windows: path-sep normalizing - file = (ts).normalizePath(file); - - if (!_cmdLine.options.configFilePath) { - // this is needed for the INTERNAL getOutputFileNames-call below... - _cmdLine.options.configFilePath = configFilePath; - } - const isDts = file.endsWith('.d.ts'); - if (isDts) { - file = file.slice(0, -5) + '.ts'; - _cmdLine.fileNames.push(file); - } - const outfile = (ts).getOutputFileNames(_cmdLine, file, true)[0]; - if (isDts) { - _cmdLine.fileNames.pop(); - } - return outfile; - - } catch (err) { - console.error(file, _cmdLine.fileNames); - console.error(err); - throw new err; - } - }; + logFn('Transpile', `will use ${TscTranspiler.P} transpile worker`); + this._outputFileNames = new OutputFileNameOracle(_cmdLine, configFilePath); } async join() { @@ -218,7 +232,7 @@ export class Transpiler { } const newLen = this._queue.push(file); - if (newLen > Transpiler.P ** 2) { + if (newLen > TscTranspiler.P ** 2) { this._consumeQueue(); } } @@ -232,8 +246,8 @@ export class Transpiler { // kinda LAZYily create workers if (this._workerPool.length === 0) { - for (let i = 0; i < Transpiler.P; i++) { - this._workerPool.push(new TranspileWorker(file => this._getOutputFileName(file))); + for (let i = 0; i < TscTranspiler.P; i++) { + this._workerPool.push(new TranspileWorker(file => this._outputFileNames.getOutputFileName(file))); } } @@ -251,7 +265,7 @@ export class Transpiler { const job = new Promise(resolve => { const consume = () => { - const files = this._queue.splice(0, Transpiler.P); + const files = this._queue.splice(0, TscTranspiler.P); if (files.length === 0) { // DONE resolve(undefined); @@ -283,3 +297,111 @@ function _isDefaultEmpty(src: string): boolean { .replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1') .trim().length === 0; } + + +export class SwcTranspiler implements ITranspiler { + + onOutfile?: ((file: Vinyl) => void) | undefined; + + private readonly _outputFileNames: OutputFileNameOracle; + private _jobs: Promise[] = []; + + constructor( + private readonly _logFn: (topic: string, message: string) => void, + private readonly _onError: (err: any) => void, + configFilePath: string, + private readonly _cmdLine: ts.ParsedCommandLine + ) { + _logFn('Transpile', `will use SWC to transpile source files`); + this._outputFileNames = new OutputFileNameOracle(_cmdLine, configFilePath); + } + + async join(): Promise { + const jobs = this._jobs.slice(); + this._jobs.length = 0; + await Promise.allSettled(jobs); + } + + transpile(file: Vinyl): void { + if (this._cmdLine.options.noEmit) { + // not doing ANYTHING here + return; + } + + const tsSrc = String(file.contents); + const t1 = Date.now(); + + let options: swc.Options = SwcTranspiler._swcrcEsm; + if (this._cmdLine.options.module === ts.ModuleKind.AMD) { + const isAmd = /\n(import|export)/m.test(tsSrc); + if (isAmd) { + options = SwcTranspiler._swcrcAmd; + } + } else if (this._cmdLine.options.module === ts.ModuleKind.CommonJS) { + options = SwcTranspiler._swcrcCommonJS; + } + + this._jobs.push(swc.transform(tsSrc, options).then(output => { + + // check if output of a DTS-files isn't just "empty" and iff so + // skip this file + if (file.path.endsWith('.d.ts') && _isDefaultEmpty(output.code)) { + return; + } + + const outBase = this._cmdLine.options.outDir ?? file.base; + const outPath = this._outputFileNames.getOutputFileName(file.path); + + this.onOutfile!(new Vinyl({ + path: outPath, + base: outBase, + contents: Buffer.from(output.code), + })); + + this._logFn('Transpile', `swc took ${Date.now() - t1}ms for ${file.path}`); + + }).catch(err => { + this._onError(err); + })); + } + + // --- .swcrc + + + private static readonly _swcrcAmd: swc.Options = { + exclude: '\.js$', + jsc: { + parser: { + syntax: 'typescript', + tsx: false, + decorators: true + }, + target: 'es2020', + loose: false, + minify: { + compress: false, + mangle: false + } + }, + module: { + type: 'amd', + noInterop: true + }, + minify: false, + }; + + private static readonly _swcrcCommonJS: swc.Options = { + ...this._swcrcAmd, + module: { + type: 'commonjs', + importInterop: 'none' + } + }; + + private static readonly _swcrcEsm: swc.Options = { + ...this._swcrcAmd, + module: { + type: 'es6' + } + }; +} diff --git a/build/lib/util.ts b/build/lib/util.ts index 2511f987fbc..9716be2290a 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -207,8 +207,8 @@ export function loadSourcemaps(): NodeJS.ReadWriteStream { const contents = (f.contents).toString('utf8'); const reg = /\/\/# sourceMappingURL=(.*)$/g; - let lastMatch: RegExpMatchArray | null = null; - let match: RegExpMatchArray | null = null; + let lastMatch: RegExpExecArray | null = null; + let match: RegExpExecArray | null = null; while (match = reg.exec(contents)) { lastMatch = match; diff --git a/build/linux/debian/calculate-deps.js b/build/linux/debian/calculate-deps.js new file mode 100644 index 00000000000..ecdb01f541c --- /dev/null +++ b/build/linux/debian/calculate-deps.js @@ -0,0 +1,79 @@ +"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 }); +exports.generatePackageDeps = void 0; +const child_process_1 = require("child_process"); +const fs_1 = require("fs"); +const os_1 = require("os"); +const path = require("path"); +const manifests = require("../../../cgmanifest.json"); +const dep_lists_1 = require("./dep-lists"); +function generatePackageDeps(files, arch, sysroot) { + const dependencies = files.map(file => calculatePackageDeps(file, arch, sysroot)); + const additionalDepsSet = new Set(dep_lists_1.additionalDeps); + dependencies.push(additionalDepsSet); + return dependencies; +} +exports.generatePackageDeps = generatePackageDeps; +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/calculate_package_deps.py. +function calculatePackageDeps(binaryPath, arch, sysroot) { + try { + if (!((0, fs_1.statSync)(binaryPath).mode & fs_1.constants.S_IXUSR)) { + throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`); + } + } + catch (e) { + // The package might not exist. Don't re-throw the error here. + console.error('Tried to stat ' + binaryPath + ' but failed.'); + } + // Get the Chromium dpkg-shlibdeps file. + const chromiumManifest = manifests.registrations.filter(registration => { + return registration.component.type === 'git' && registration.component.git.name === 'chromium'; + }); + const dpkgShlibdepsUrl = `https://raw.githubusercontent.com/chromium/chromium/${chromiumManifest[0].version}/third_party/dpkg-shlibdeps/dpkg-shlibdeps.pl`; + const dpkgShlibdepsScriptLocation = `${(0, os_1.tmpdir)()}/dpkg-shlibdeps.pl`; + const result = (0, child_process_1.spawnSync)('curl', [dpkgShlibdepsUrl, '-o', dpkgShlibdepsScriptLocation]); + if (result.status !== 0) { + throw new Error('Cannot retrieve dpkg-shlibdeps. Stderr:\n' + result.stderr); + } + const cmd = [dpkgShlibdepsScriptLocation, '--ignore-weak-undefined']; + switch (arch) { + case 'amd64': + cmd.push(`-l${sysroot}/usr/lib/x86_64-linux-gnu`, `-l${sysroot}/lib/x86_64-linux-gnu`); + break; + case 'armhf': + cmd.push(`-l${sysroot}/usr/lib/arm-linux-gnueabihf`, `-l${sysroot}/lib/arm-linux-gnueabihf`); + break; + case 'arm64': + cmd.push(`-l${sysroot}/usr/lib/aarch64-linux-gnu`, `-l${sysroot}/lib/aarch64-linux-gnu`); + break; + } + cmd.push(`-l${sysroot}/usr/lib`); + cmd.push('-O', '-e', path.resolve(binaryPath)); + const dpkgShlibdepsResult = (0, child_process_1.spawnSync)('perl', cmd, { cwd: sysroot }); + if (dpkgShlibdepsResult.status !== 0) { + throw new Error(`dpkg-shlibdeps failed with exit code ${dpkgShlibdepsResult.status}. stderr:\n${dpkgShlibdepsResult.stderr} `); + } + const shlibsDependsPrefix = 'shlibs:Depends='; + const requiresList = dpkgShlibdepsResult.stdout.toString('utf-8').trimEnd().split('\n'); + let depsStr = ''; + for (const line of requiresList) { + if (line.startsWith(shlibsDependsPrefix)) { + depsStr = line.substring(shlibsDependsPrefix.length); + } + } + // Refs https://chromium-review.googlesource.com/c/chromium/src/+/3572926 + // Chromium depends on libgcc_s, is from the package libgcc1. However, in + // Bullseye, the package was renamed to libgcc-s1. To avoid adding a dep + // on the newer package, this hack skips the dep. This is safe because + // libgcc-s1 is a dependency of libc6. This hack can be removed once + // support for Debian Buster and Ubuntu Bionic are dropped. + const filteredDeps = depsStr.split(', ').filter(dependency => { + return !dependency.startsWith('libgcc-s1'); + }).sort(); + const requires = new Set(filteredDeps); + return requires; +} diff --git a/build/linux/debian/calculate-deps.ts b/build/linux/debian/calculate-deps.ts new file mode 100644 index 00000000000..b13d3cdfaaf --- /dev/null +++ b/build/linux/debian/calculate-deps.ts @@ -0,0 +1,84 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { spawnSync } from 'child_process'; +import { constants, statSync } from 'fs'; +import { tmpdir } from 'os'; +import path = require('path'); +import * as manifests from '../../../cgmanifest.json'; +import { additionalDeps } from './dep-lists'; +import { DebianArchString } from './types'; + +export function generatePackageDeps(files: string[], arch: DebianArchString, sysroot: string): Set[] { + const dependencies: Set[] = files.map(file => calculatePackageDeps(file, arch, sysroot)); + const additionalDepsSet = new Set(additionalDeps); + dependencies.push(additionalDepsSet); + return dependencies; +} + +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/calculate_package_deps.py. +function calculatePackageDeps(binaryPath: string, arch: DebianArchString, sysroot: string): Set { + try { + if (!(statSync(binaryPath).mode & constants.S_IXUSR)) { + throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`); + } + } catch (e) { + // The package might not exist. Don't re-throw the error here. + console.error('Tried to stat ' + binaryPath + ' but failed.'); + } + + // Get the Chromium dpkg-shlibdeps file. + const chromiumManifest = manifests.registrations.filter(registration => { + return registration.component.type === 'git' && registration.component.git!.name === 'chromium'; + }); + const dpkgShlibdepsUrl = `https://raw.githubusercontent.com/chromium/chromium/${chromiumManifest[0].version}/third_party/dpkg-shlibdeps/dpkg-shlibdeps.pl`; + const dpkgShlibdepsScriptLocation = `${tmpdir()}/dpkg-shlibdeps.pl`; + const result = spawnSync('curl', [dpkgShlibdepsUrl, '-o', dpkgShlibdepsScriptLocation]); + if (result.status !== 0) { + throw new Error('Cannot retrieve dpkg-shlibdeps. Stderr:\n' + result.stderr); + } + const cmd = [dpkgShlibdepsScriptLocation, '--ignore-weak-undefined']; + switch (arch) { + case 'amd64': + cmd.push(`-l${sysroot}/usr/lib/x86_64-linux-gnu`, + `-l${sysroot}/lib/x86_64-linux-gnu`); + break; + case 'armhf': + cmd.push(`-l${sysroot}/usr/lib/arm-linux-gnueabihf`, + `-l${sysroot}/lib/arm-linux-gnueabihf`); + break; + case 'arm64': + cmd.push(`-l${sysroot}/usr/lib/aarch64-linux-gnu`, + `-l${sysroot}/lib/aarch64-linux-gnu`); + break; + } + cmd.push(`-l${sysroot}/usr/lib`); + cmd.push('-O', '-e', path.resolve(binaryPath)); + + const dpkgShlibdepsResult = spawnSync('perl', cmd, { cwd: sysroot }); + if (dpkgShlibdepsResult.status !== 0) { + throw new Error(`dpkg-shlibdeps failed with exit code ${dpkgShlibdepsResult.status}. stderr:\n${dpkgShlibdepsResult.stderr} `); + } + + const shlibsDependsPrefix = 'shlibs:Depends='; + const requiresList = dpkgShlibdepsResult.stdout.toString('utf-8').trimEnd().split('\n'); + let depsStr = ''; + for (const line of requiresList) { + if (line.startsWith(shlibsDependsPrefix)) { + depsStr = line.substring(shlibsDependsPrefix.length); + } + } + // Refs https://chromium-review.googlesource.com/c/chromium/src/+/3572926 + // Chromium depends on libgcc_s, is from the package libgcc1. However, in + // Bullseye, the package was renamed to libgcc-s1. To avoid adding a dep + // on the newer package, this hack skips the dep. This is safe because + // libgcc-s1 is a dependency of libc6. This hack can be removed once + // support for Debian Buster and Ubuntu Bionic are dropped. + const filteredDeps = depsStr.split(', ').filter(dependency => { + return !dependency.startsWith('libgcc-s1'); + }).sort(); + const requires = new Set(filteredDeps); + return requires; +} diff --git a/build/linux/debian/dep-lists.js b/build/linux/debian/dep-lists.js new file mode 100644 index 00000000000..f61968c5170 --- /dev/null +++ b/build/linux/debian/dep-lists.js @@ -0,0 +1,141 @@ +"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 }); +exports.referenceGeneratedDepsByArch = exports.recommendedDeps = exports.additionalDeps = void 0; +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/additional_deps +// Additional dependencies not in the dpkg-shlibdeps output. +exports.additionalDeps = [ + 'ca-certificates', + 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', + 'libnss3 (>= 3.26)', + 'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', + 'xdg-utils (>= 1.0.2)' // OS integration +]; +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/manual_recommends +// Dependencies that we can only recommend +// for now since some of the older distros don't support them. +exports.recommendedDeps = [ + 'libvulkan1' // Move to additionalDeps once support for Trusty and Jessie are dropped. +]; +exports.referenceGeneratedDepsByArch = { + 'amd64': [ + 'ca-certificates', + 'libasound2 (>= 1.0.16)', + 'libatk-bridge2.0-0 (>= 2.5.3)', + 'libatk1.0-0 (>= 2.2.0)', + 'libatspi2.0-0 (>= 2.9.90)', + 'libc6 (>= 2.14)', + 'libc6 (>= 2.17)', + 'libc6 (>= 2.2.5)', + 'libcairo2 (>= 1.6.0)', + 'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', + 'libdbus-1-3 (>= 1.5.12)', + 'libdrm2 (>= 2.4.38)', + 'libexpat1 (>= 2.0.1)', + 'libgbm1 (>= 8.1~0)', + 'libglib2.0-0 (>= 2.16.0)', + 'libglib2.0-0 (>= 2.39.4)', + 'libgtk-3-0 (>= 3.9.10)', + 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', + 'libnspr4 (>= 2:4.9-2~)', + 'libnss3 (>= 2:3.22)', + 'libnss3 (>= 3.26)', + 'libpango-1.0-0 (>= 1.14.0)', + 'libsecret-1-0 (>= 0.18)', + 'libx11-6', + 'libx11-6 (>= 2:1.4.99.1)', + 'libxcb1 (>= 1.9.2)', + 'libxcomposite1 (>= 1:0.4.4-1)', + 'libxdamage1 (>= 1:1.1)', + 'libxext6', + 'libxfixes3', + 'libxkbcommon0 (>= 0.4.1)', + 'libxkbfile1', + 'libxrandr2', + 'xdg-utils (>= 1.0.2)' + ], + 'armhf': [ + 'ca-certificates', + 'libasound2 (>= 1.0.16)', + 'libatk-bridge2.0-0 (>= 2.5.3)', + 'libatk1.0-0 (>= 2.2.0)', + 'libatspi2.0-0 (>= 2.9.90)', + 'libc6 (>= 2.17)', + 'libc6 (>= 2.4)', + 'libc6 (>= 2.9)', + 'libcairo2 (>= 1.6.0)', + 'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', + 'libdbus-1-3 (>= 1.5.12)', + 'libdrm2 (>= 2.4.38)', + 'libexpat1 (>= 2.0.1)', + 'libgbm1 (>= 8.1~0)', + 'libglib2.0-0 (>= 2.16.0)', + 'libglib2.0-0 (>= 2.39.4)', + 'libgtk-3-0 (>= 3.9.10)', + 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', + 'libnspr4 (>= 2:4.9-2~)', + 'libnss3 (>= 2:3.22)', + 'libnss3 (>= 3.26)', + 'libpango-1.0-0 (>= 1.14.0)', + 'libsecret-1-0 (>= 0.18)', + 'libstdc++6 (>= 4.1.1)', + 'libstdc++6 (>= 5)', + 'libstdc++6 (>= 5.2)', + 'libstdc++6 (>= 6)', + 'libx11-6', + 'libx11-6 (>= 2:1.4.99.1)', + 'libxcb1 (>= 1.9.2)', + 'libxcomposite1 (>= 1:0.4.4-1)', + 'libxdamage1 (>= 1:1.1)', + 'libxext6', + 'libxfixes3', + 'libxkbcommon0 (>= 0.4.1)', + 'libxkbfile1', + 'libxrandr2', + 'xdg-utils (>= 1.0.2)' + ], + 'arm64': [ + 'ca-certificates', + 'libasound2 (>= 1.0.16)', + 'libatk-bridge2.0-0 (>= 2.5.3)', + 'libatk1.0-0 (>= 2.2.0)', + 'libatspi2.0-0 (>= 2.9.90)', + 'libc6 (>= 2.17)', + 'libcairo2 (>= 1.6.0)', + 'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', + 'libdbus-1-3 (>= 1.0.2)', + 'libdrm2 (>= 2.4.38)', + 'libexpat1 (>= 2.0.1)', + 'libgbm1 (>= 8.1~0)', + 'libgcc1 (>= 1:3.0)', + 'libgcc1 (>= 1:4.2)', + 'libgcc1 (>= 1:4.5)', + 'libglib2.0-0 (>= 2.16.0)', + 'libglib2.0-0 (>= 2.39.4)', + 'libgtk-3-0 (>= 3.9.10)', + 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', + 'libnspr4 (>= 2:4.9-2~)', + 'libnss3 (>= 2:3.22)', + 'libnss3 (>= 3.26)', + 'libpango-1.0-0 (>= 1.14.0)', + 'libsecret-1-0 (>= 0.18)', + 'libstdc++6 (>= 4.1.1)', + 'libstdc++6 (>= 5)', + 'libstdc++6 (>= 5.2)', + 'libstdc++6 (>= 6)', + 'libx11-6', + 'libx11-6 (>= 2:1.4.99.1)', + 'libxcb1 (>= 1.9.2)', + 'libxcomposite1 (>= 1:0.4.4-1)', + 'libxdamage1 (>= 1:1.1)', + 'libxext6', + 'libxfixes3', + 'libxkbcommon0 (>= 0.4.1)', + 'libxkbfile1', + 'libxrandr2', + 'xdg-utils (>= 1.0.2)' + ] +}; diff --git a/build/linux/debian/dep-lists.ts b/build/linux/debian/dep-lists.ts new file mode 100644 index 00000000000..63b14bf16f0 --- /dev/null +++ b/build/linux/debian/dep-lists.ts @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/additional_deps +// Additional dependencies not in the dpkg-shlibdeps output. +export const additionalDeps = [ + 'ca-certificates', // Make sure users have SSL certificates. + 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', + 'libnss3 (>= 3.26)', + 'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', // For Breakpad crash reports. + 'xdg-utils (>= 1.0.2)' // OS integration +]; + +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/manual_recommends +// Dependencies that we can only recommend +// for now since some of the older distros don't support them. +export const recommendedDeps = [ + 'libvulkan1' // Move to additionalDeps once support for Trusty and Jessie are dropped. +]; + +export const referenceGeneratedDepsByArch = { + 'amd64': [ + 'ca-certificates', + 'libasound2 (>= 1.0.16)', + 'libatk-bridge2.0-0 (>= 2.5.3)', + 'libatk1.0-0 (>= 2.2.0)', + 'libatspi2.0-0 (>= 2.9.90)', + 'libc6 (>= 2.14)', + 'libc6 (>= 2.17)', + 'libc6 (>= 2.2.5)', + 'libcairo2 (>= 1.6.0)', + 'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', + 'libdbus-1-3 (>= 1.5.12)', + 'libdrm2 (>= 2.4.38)', + 'libexpat1 (>= 2.0.1)', + 'libgbm1 (>= 8.1~0)', + 'libglib2.0-0 (>= 2.16.0)', + 'libglib2.0-0 (>= 2.39.4)', + 'libgtk-3-0 (>= 3.9.10)', + 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', + 'libnspr4 (>= 2:4.9-2~)', + 'libnss3 (>= 2:3.22)', + 'libnss3 (>= 3.26)', + 'libpango-1.0-0 (>= 1.14.0)', + 'libsecret-1-0 (>= 0.18)', + 'libx11-6', + 'libx11-6 (>= 2:1.4.99.1)', + 'libxcb1 (>= 1.9.2)', + 'libxcomposite1 (>= 1:0.4.4-1)', + 'libxdamage1 (>= 1:1.1)', + 'libxext6', + 'libxfixes3', + 'libxkbcommon0 (>= 0.4.1)', + 'libxkbfile1', + 'libxrandr2', + 'xdg-utils (>= 1.0.2)' + ], + 'armhf': [ + 'ca-certificates', + 'libasound2 (>= 1.0.16)', + 'libatk-bridge2.0-0 (>= 2.5.3)', + 'libatk1.0-0 (>= 2.2.0)', + 'libatspi2.0-0 (>= 2.9.90)', + 'libc6 (>= 2.17)', + 'libc6 (>= 2.4)', + 'libc6 (>= 2.9)', + 'libcairo2 (>= 1.6.0)', + 'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', + 'libdbus-1-3 (>= 1.5.12)', + 'libdrm2 (>= 2.4.38)', + 'libexpat1 (>= 2.0.1)', + 'libgbm1 (>= 8.1~0)', + 'libglib2.0-0 (>= 2.16.0)', + 'libglib2.0-0 (>= 2.39.4)', + 'libgtk-3-0 (>= 3.9.10)', + 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', + 'libnspr4 (>= 2:4.9-2~)', + 'libnss3 (>= 2:3.22)', + 'libnss3 (>= 3.26)', + 'libpango-1.0-0 (>= 1.14.0)', + 'libsecret-1-0 (>= 0.18)', + 'libstdc++6 (>= 4.1.1)', + 'libstdc++6 (>= 5)', + 'libstdc++6 (>= 5.2)', + 'libstdc++6 (>= 6)', + 'libx11-6', + 'libx11-6 (>= 2:1.4.99.1)', + 'libxcb1 (>= 1.9.2)', + 'libxcomposite1 (>= 1:0.4.4-1)', + 'libxdamage1 (>= 1:1.1)', + 'libxext6', + 'libxfixes3', + 'libxkbcommon0 (>= 0.4.1)', + 'libxkbfile1', + 'libxrandr2', + 'xdg-utils (>= 1.0.2)' + ], + 'arm64': [ + 'ca-certificates', + 'libasound2 (>= 1.0.16)', + 'libatk-bridge2.0-0 (>= 2.5.3)', + 'libatk1.0-0 (>= 2.2.0)', + 'libatspi2.0-0 (>= 2.9.90)', + 'libc6 (>= 2.17)', + 'libcairo2 (>= 1.6.0)', + 'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', + 'libdbus-1-3 (>= 1.0.2)', + 'libdrm2 (>= 2.4.38)', + 'libexpat1 (>= 2.0.1)', + 'libgbm1 (>= 8.1~0)', + 'libgcc1 (>= 1:3.0)', + 'libgcc1 (>= 1:4.2)', + 'libgcc1 (>= 1:4.5)', + 'libglib2.0-0 (>= 2.16.0)', + 'libglib2.0-0 (>= 2.39.4)', + 'libgtk-3-0 (>= 3.9.10)', + 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', + 'libnspr4 (>= 2:4.9-2~)', + 'libnss3 (>= 2:3.22)', + 'libnss3 (>= 3.26)', + 'libpango-1.0-0 (>= 1.14.0)', + 'libsecret-1-0 (>= 0.18)', + 'libstdc++6 (>= 4.1.1)', + 'libstdc++6 (>= 5)', + 'libstdc++6 (>= 5.2)', + 'libstdc++6 (>= 6)', + 'libx11-6', + 'libx11-6 (>= 2:1.4.99.1)', + 'libxcb1 (>= 1.9.2)', + 'libxcomposite1 (>= 1:0.4.4-1)', + 'libxdamage1 (>= 1:1.1)', + 'libxext6', + 'libxfixes3', + 'libxkbcommon0 (>= 0.4.1)', + 'libxkbfile1', + 'libxrandr2', + 'xdg-utils (>= 1.0.2)' + ] +}; diff --git a/build/linux/debian/install-sysroot.js b/build/linux/debian/install-sysroot.js new file mode 100644 index 00000000000..2eaec091873 --- /dev/null +++ b/build/linux/debian/install-sysroot.js @@ -0,0 +1,89 @@ +"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 }); +exports.getSysroot = void 0; +const child_process_1 = require("child_process"); +const crypto_1 = require("crypto"); +const os_1 = require("os"); +const fs = require("fs"); +const https = require("https"); +const path = require("path"); +const util = require("../../lib/util"); +// Based on https://source.chromium.org/chromium/chromium/src/+/main:build/linux/sysroot_scripts/install-sysroot.py. +const URL_PREFIX = 'https://msftelectron.blob.core.windows.net'; +const URL_PATH = 'sysroots/toolchain'; +function getSha(filename) { + const hash = (0, crypto_1.createHash)('sha1'); + // Read file 1 MB at a time + const fd = fs.openSync(filename, 'r'); + const buffer = Buffer.alloc(1024 * 1024); + let position = 0; + let bytesRead = 0; + while ((bytesRead = fs.readSync(fd, buffer, 0, buffer.length, position)) === buffer.length) { + hash.update(buffer); + position += bytesRead; + } + hash.update(buffer.slice(0, bytesRead)); + return hash.digest('hex'); +} +async function getSysroot(arch) { + const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion()}/script/sysroots.json`; + const sysrootDictLocation = `${(0, os_1.tmpdir)()}/sysroots.json`; + const result = (0, child_process_1.spawnSync)('curl', [sysrootJSONUrl, '-o', sysrootDictLocation]); + if (result.status !== 0) { + throw new Error('Cannot retrieve sysroots.json. Stderr:\n' + result.stderr); + } + const sysrootInfo = require(sysrootDictLocation); + const sysrootArch = arch === 'armhf' ? 'bullseye_arm' : `bullseye_${arch}`; + const sysrootDict = sysrootInfo[sysrootArch]; + const tarballFilename = sysrootDict['Tarball']; + const tarballSha = sysrootDict['Sha1Sum']; + const sysroot = path.join((0, os_1.tmpdir)(), sysrootDict['SysrootDir']); + const url = [URL_PREFIX, URL_PATH, tarballSha, tarballFilename].join('/'); + const stamp = path.join(sysroot, '.stamp'); + if (fs.existsSync(stamp) && fs.readFileSync(stamp).toString() === url) { + return sysroot; + } + console.log(`Installing Debian ${arch} root image: ${sysroot}`); + fs.rmSync(sysroot, { recursive: true, force: true }); + fs.mkdirSync(sysroot); + const tarball = path.join(sysroot, tarballFilename); + console.log(`Downloading ${url}`); + let downloadSuccess = false; + for (let i = 0; i < 3 && !downloadSuccess; i++) { + fs.writeFileSync(tarball, ''); + await new Promise((c) => { + https.get(url, (res) => { + res.on('data', (chunk) => { + fs.appendFileSync(tarball, chunk); + }); + res.on('end', () => { + downloadSuccess = true; + c(); + }); + }).on('error', (err) => { + console.error('Encountered an error during the download attempt: ' + err.message); + c(); + }); + }); + } + if (!downloadSuccess) { + fs.rmSync(tarball); + throw new Error('Failed to download ' + url); + } + const sha = getSha(tarball); + if (sha !== tarballSha) { + throw new Error(`Tarball sha1sum is wrong. Expected ${tarballSha}, actual ${sha}`); + } + const proc = (0, child_process_1.spawnSync)('tar', ['xf', tarball, '-C', sysroot]); + if (proc.status) { + throw new Error('Tarball extraction failed with code ' + proc.status); + } + fs.rmSync(tarball); + fs.writeFileSync(stamp, url); + return sysroot; +} +exports.getSysroot = getSysroot; diff --git a/build/linux/debian/install-sysroot.ts b/build/linux/debian/install-sysroot.ts new file mode 100644 index 00000000000..ac9de5b8578 --- /dev/null +++ b/build/linux/debian/install-sysroot.ts @@ -0,0 +1,98 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { spawnSync } from 'child_process'; +import { createHash } from 'crypto'; +import { tmpdir } from 'os'; +import * as fs from 'fs'; +import * as https from 'https'; +import * as path from 'path'; +import { DebianArchString } from './types'; +import * as util from '../../lib/util'; + +// Based on https://source.chromium.org/chromium/chromium/src/+/main:build/linux/sysroot_scripts/install-sysroot.py. +const URL_PREFIX = 'https://msftelectron.blob.core.windows.net'; +const URL_PATH = 'sysroots/toolchain'; + +function getSha(filename: fs.PathLike): string { + const hash = createHash('sha1'); + // Read file 1 MB at a time + const fd = fs.openSync(filename, 'r'); + const buffer = Buffer.alloc(1024 * 1024); + let position = 0; + let bytesRead = 0; + while ((bytesRead = fs.readSync(fd, buffer, 0, buffer.length, position)) === buffer.length) { + hash.update(buffer); + position += bytesRead; + } + hash.update(buffer.slice(0, bytesRead)); + return hash.digest('hex'); +} + +type SysrootDictEntry = { + Sha1Sum: string; + SysrootDir: string; + Tarball: string; +}; + +export async function getSysroot(arch: DebianArchString): Promise { + const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion()}/script/sysroots.json`; + const sysrootDictLocation = `${tmpdir()}/sysroots.json`; + const result = spawnSync('curl', [sysrootJSONUrl, '-o', sysrootDictLocation]); + if (result.status !== 0) { + throw new Error('Cannot retrieve sysroots.json. Stderr:\n' + result.stderr); + } + const sysrootInfo = require(sysrootDictLocation); + const sysrootArch = arch === 'armhf' ? 'bullseye_arm' : `bullseye_${arch}`; + const sysrootDict: SysrootDictEntry = sysrootInfo[sysrootArch]; + const tarballFilename = sysrootDict['Tarball']; + const tarballSha = sysrootDict['Sha1Sum']; + const sysroot = path.join(tmpdir(), sysrootDict['SysrootDir']); + const url = [URL_PREFIX, URL_PATH, tarballSha, tarballFilename].join('/'); + const stamp = path.join(sysroot, '.stamp'); + if (fs.existsSync(stamp) && fs.readFileSync(stamp).toString() === url) { + return sysroot; + } + + console.log(`Installing Debian ${arch} root image: ${sysroot}`); + fs.rmSync(sysroot, { recursive: true, force: true }); + fs.mkdirSync(sysroot); + const tarball = path.join(sysroot, tarballFilename); + console.log(`Downloading ${url}`); + let downloadSuccess = false; + for (let i = 0; i < 3 && !downloadSuccess; i++) { + fs.writeFileSync(tarball, ''); + await new Promise((c) => { + https.get(url, (res) => { + res.on('data', (chunk) => { + fs.appendFileSync(tarball, chunk); + }); + res.on('end', () => { + downloadSuccess = true; + c(); + }); + }).on('error', (err) => { + console.error('Encountered an error during the download attempt: ' + err.message); + c(); + }); + }); + } + if (!downloadSuccess) { + fs.rmSync(tarball); + throw new Error('Failed to download ' + url); + } + const sha = getSha(tarball); + if (sha !== tarballSha) { + throw new Error(`Tarball sha1sum is wrong. Expected ${tarballSha}, actual ${sha}`); + } + + const proc = spawnSync('tar', ['xf', tarball, '-C', sysroot]); + if (proc.status) { + throw new Error('Tarball extraction failed with code ' + proc.status); + } + fs.rmSync(tarball); + fs.writeFileSync(stamp, url); + return sysroot; +} diff --git a/build/linux/debian/types.js b/build/linux/debian/types.js new file mode 100644 index 00000000000..93c92aac9c6 --- /dev/null +++ b/build/linux/debian/types.js @@ -0,0 +1,11 @@ +"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 }); +exports.isDebianArchString = void 0; +function isDebianArchString(s) { + return ['amd64', 'armhf', 'arm64'].includes(s); +} +exports.isDebianArchString = isDebianArchString; diff --git a/build/linux/debian/types.ts b/build/linux/debian/types.ts new file mode 100644 index 00000000000..e97485ef128 --- /dev/null +++ b/build/linux/debian/types.ts @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export type DebianArchString = 'amd64' | 'armhf' | 'arm64'; + +export function isDebianArchString(s: string): s is DebianArchString { + return ['amd64', 'armhf', 'arm64'].includes(s); +} diff --git a/build/linux/rpm/dependencies-generator.js b/build/linux/dependencies-generator.js similarity index 57% rename from build/linux/rpm/dependencies-generator.js rename to build/linux/dependencies-generator.js index 3b1e404129c..af20828097e 100644 --- a/build/linux/rpm/dependencies-generator.js +++ b/build/linux/dependencies-generator.js @@ -1,23 +1,50 @@ -"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDependencies = void 0; const child_process_1 = require("child_process"); -const fs_1 = require("fs"); const path = require("path"); -const dep_lists_1 = require("./dep-lists"); +const calculate_deps_1 = require("./debian/calculate-deps"); +const calculate_deps_2 = require("./rpm/calculate-deps"); +const dep_lists_1 = require("./debian/dep-lists"); +const dep_lists_2 = require("./rpm/dep-lists"); +const types_1 = require("./debian/types"); +const types_2 = require("./rpm/types"); // A flag that can easily be toggled. // Make sure to compile the build directory after toggling the value. // If false, we warn about new dependencies if they show up -// while running the rpm prepare package task for a release. +// while running the prepare package tasks for a release. // If true, we fail the build if there are new dependencies found during that task. // The reference dependencies, which one has to update when the new dependencies // are valid, are in dep-lists.ts const FAIL_BUILD_FOR_NEW_DEPENDENCIES = true; -function getDependencies(buildDir, applicationName, arch) { +// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:chrome/installer/linux/BUILD.gn;l=64-80 +// and the Linux Archive build +// Shared library dependencies that we already bundle. +const bundledDeps = [ + 'libEGL.so', + 'libGLESv2.so', + 'libvulkan.so.1', + 'swiftshader_libEGL.so', + 'swiftshader_libGLESv2.so', + 'libvk_swiftshader.so', + 'libffmpeg.so' +]; +function getDependencies(packageType, buildDir, applicationName, arch, sysroot) { + if (packageType === 'deb') { + if (!(0, types_1.isDebianArchString)(arch)) { + throw new Error('Invalid Debian arch string ' + arch); + } + if (!sysroot) { + throw new Error('Missing sysroot parameter'); + } + } + if (packageType === 'rpm' && !(0, types_2.isRpmArchString)(arch)) { + throw new Error('Invalid RPM arch string ' + arch); + } // Get the files for which we want to find dependencies. const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked'); const findResult = (0, child_process_1.spawnSync)('find', [nativeModulesPath, '-name', '*.node']); @@ -33,26 +60,22 @@ function getDependencies(buildDir, applicationName, arch) { files.push(path.join(buildDir, 'chrome-sandbox')); files.push(path.join(buildDir, 'chrome_crashpad_handler')); // Generate the dependencies. - const dependencies = files.map((file) => calculatePackageDeps(file)); - // Add additional dependencies. - const additionalDepsSet = new Set(dep_lists_1.additionalDeps); - dependencies.push(additionalDepsSet); + const dependencies = packageType === 'deb' ? + (0, calculate_deps_1.generatePackageDeps)(files, arch, sysroot) : + (0, calculate_deps_2.generatePackageDeps)(files); // Merge all the dependencies. const mergedDependencies = mergePackageDeps(dependencies); - let sortedDependencies = []; - for (const dependency of mergedDependencies) { - sortedDependencies.push(dependency); - } - sortedDependencies.sort(); - // Exclude bundled dependencies - sortedDependencies = sortedDependencies.filter(dependency => { - return !dep_lists_1.bundledDeps.some(bundledDep => dependency.startsWith(bundledDep)); - }); - const referenceGeneratedDeps = dep_lists_1.referenceGeneratedDepsByArch[arch]; + // Exclude bundled dependencies and sort + const sortedDependencies = Array.from(mergedDependencies).filter(dependency => { + return !bundledDeps.some(bundledDep => dependency.startsWith(bundledDep)); + }).sort(); + const referenceGeneratedDeps = packageType === 'deb' ? + dep_lists_1.referenceGeneratedDepsByArch[arch] : + dep_lists_2.referenceGeneratedDepsByArch[arch]; if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) { - const failMessage = 'The dependencies list has changed. ' - + 'Printing newer dependencies list that one can use to compare against referenceGeneratedDeps:\n' - + sortedDependencies.join('\n'); + const failMessage = 'The dependencies list has changed.' + + '\nOld:\n' + referenceGeneratedDeps.join('\n') + + '\nNew:\n' + sortedDependencies.join('\n'); if (FAIL_BUILD_FOR_NEW_DEPENDENCIES) { throw new Error(failMessage); } @@ -63,25 +86,7 @@ function getDependencies(buildDir, applicationName, arch) { return sortedDependencies; } exports.getDependencies = getDependencies; -// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/calculate_package_deps.py. -function calculatePackageDeps(binaryPath) { - try { - if (!((0, fs_1.statSync)(binaryPath).mode & fs_1.constants.S_IXUSR)) { - throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`); - } - } - catch (e) { - // The package might not exist. Don't re-throw the error here. - console.error('Tried to stat ' + binaryPath + ' but failed.'); - } - const findRequiresResult = (0, child_process_1.spawnSync)('/usr/lib/rpm/find-requires', { input: binaryPath + '\n' }); - if (findRequiresResult.status !== 0) { - throw new Error(`find-requires failed with exit code ${findRequiresResult.status}.\nstderr: ${findRequiresResult.stderr}`); - } - const requires = new Set(findRequiresResult.stdout.toString('utf-8').trimEnd().split('\n')); - return requires; -} -// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/merge_package_deps.py +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/merge_package_deps.py. function mergePackageDeps(inputDeps) { const requires = new Set(); for (const depSet of inputDeps) { diff --git a/build/linux/rpm/dependencies-generator.ts b/build/linux/dependencies-generator.ts similarity index 55% rename from build/linux/rpm/dependencies-generator.ts rename to build/linux/dependencies-generator.ts index e33210284dc..34573c4ac12 100644 --- a/build/linux/rpm/dependencies-generator.ts +++ b/build/linux/dependencies-generator.ts @@ -3,22 +3,52 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +'use strict'; + import { spawnSync } from 'child_process'; -import { constants, statSync } from 'fs'; import path = require('path'); -import { additionalDeps, bundledDeps, referenceGeneratedDepsByArch } from './dep-lists'; -import { ArchString } from './types'; +import { generatePackageDeps as generatePackageDepsDebian } from './debian/calculate-deps'; +import { generatePackageDeps as generatePackageDepsRpm } from './rpm/calculate-deps'; +import { referenceGeneratedDepsByArch as debianGeneratedDeps } from './debian/dep-lists'; +import { referenceGeneratedDepsByArch as rpmGeneratedDeps } from './rpm/dep-lists'; +import { DebianArchString, isDebianArchString } from './debian/types'; +import { isRpmArchString, RpmArchString } from './rpm/types'; // A flag that can easily be toggled. // Make sure to compile the build directory after toggling the value. // If false, we warn about new dependencies if they show up -// while running the rpm prepare package task for a release. +// while running the prepare package tasks for a release. // If true, we fail the build if there are new dependencies found during that task. // The reference dependencies, which one has to update when the new dependencies // are valid, are in dep-lists.ts const FAIL_BUILD_FOR_NEW_DEPENDENCIES: boolean = true; -export function getDependencies(buildDir: string, applicationName: string, arch: ArchString): string[] { +// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:chrome/installer/linux/BUILD.gn;l=64-80 +// and the Linux Archive build +// Shared library dependencies that we already bundle. +const bundledDeps = [ + 'libEGL.so', + 'libGLESv2.so', + 'libvulkan.so.1', + 'swiftshader_libEGL.so', + 'swiftshader_libGLESv2.so', + 'libvk_swiftshader.so', + 'libffmpeg.so' +]; + +export function getDependencies(packageType: 'deb' | 'rpm', buildDir: string, applicationName: string, arch: string, sysroot?: string): string[] { + if (packageType === 'deb') { + if (!isDebianArchString(arch)) { + throw new Error('Invalid Debian arch string ' + arch); + } + if (!sysroot) { + throw new Error('Missing sysroot parameter'); + } + } + if (packageType === 'rpm' && !isRpmArchString(arch)) { + throw new Error('Invalid RPM arch string ' + arch); + } + // Get the files for which we want to find dependencies. const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked'); const findResult = spawnSync('find', [nativeModulesPath, '-name', '*.node']); @@ -38,30 +68,25 @@ export function getDependencies(buildDir: string, applicationName: string, arch: files.push(path.join(buildDir, 'chrome_crashpad_handler')); // Generate the dependencies. - const dependencies: Set[] = files.map((file) => calculatePackageDeps(file)); - - // Add additional dependencies. - const additionalDepsSet = new Set(additionalDeps); - dependencies.push(additionalDepsSet); + const dependencies = packageType === 'deb' ? + generatePackageDepsDebian(files, arch as DebianArchString, sysroot!) : + generatePackageDepsRpm(files); // Merge all the dependencies. const mergedDependencies = mergePackageDeps(dependencies); - let sortedDependencies: string[] = []; - for (const dependency of mergedDependencies) { - sortedDependencies.push(dependency); - } - sortedDependencies.sort(); - // Exclude bundled dependencies - sortedDependencies = sortedDependencies.filter(dependency => { + // Exclude bundled dependencies and sort + const sortedDependencies: string[] = Array.from(mergedDependencies).filter(dependency => { return !bundledDeps.some(bundledDep => dependency.startsWith(bundledDep)); - }); + }).sort(); - const referenceGeneratedDeps = referenceGeneratedDepsByArch[arch]; + const referenceGeneratedDeps = packageType === 'deb' ? + debianGeneratedDeps[arch as DebianArchString] : + rpmGeneratedDeps[arch as RpmArchString]; if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) { - const failMessage = 'The dependencies list has changed. ' - + 'Printing newer dependencies list that one can use to compare against referenceGeneratedDeps:\n' - + sortedDependencies.join('\n'); + const failMessage = 'The dependencies list has changed.' + + '\nOld:\n' + referenceGeneratedDeps.join('\n') + + '\nNew:\n' + sortedDependencies.join('\n'); if (FAIL_BUILD_FOR_NEW_DEPENDENCIES) { throw new Error(failMessage); } else { @@ -72,27 +97,8 @@ export function getDependencies(buildDir: string, applicationName: string, arch: return sortedDependencies; } -// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/calculate_package_deps.py. -function calculatePackageDeps(binaryPath: string): Set { - try { - if (!(statSync(binaryPath).mode & constants.S_IXUSR)) { - throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`); - } - } catch (e) { - // The package might not exist. Don't re-throw the error here. - console.error('Tried to stat ' + binaryPath + ' but failed.'); - } - const findRequiresResult = spawnSync('/usr/lib/rpm/find-requires', { input: binaryPath + '\n' }); - if (findRequiresResult.status !== 0) { - throw new Error(`find-requires failed with exit code ${findRequiresResult.status}.\nstderr: ${findRequiresResult.stderr}`); - } - - const requires = new Set(findRequiresResult.stdout.toString('utf-8').trimEnd().split('\n')); - return requires; -} - -// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/merge_package_deps.py +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/merge_package_deps.py. function mergePackageDeps(inputDeps: Set[]): Set { const requires = new Set(); for (const depSet of inputDeps) { diff --git a/build/linux/rpm/calculate-deps.js b/build/linux/rpm/calculate-deps.js new file mode 100644 index 00000000000..325fc9694c3 --- /dev/null +++ b/build/linux/rpm/calculate-deps.js @@ -0,0 +1,35 @@ +"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 }); +exports.generatePackageDeps = void 0; +const child_process_1 = require("child_process"); +const fs_1 = require("fs"); +const dep_lists_1 = require("./dep-lists"); +function generatePackageDeps(files) { + const dependencies = files.map(file => calculatePackageDeps(file)); + const additionalDepsSet = new Set(dep_lists_1.additionalDeps); + dependencies.push(additionalDepsSet); + return dependencies; +} +exports.generatePackageDeps = generatePackageDeps; +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/calculate_package_deps.py. +function calculatePackageDeps(binaryPath) { + try { + if (!((0, fs_1.statSync)(binaryPath).mode & fs_1.constants.S_IXUSR)) { + throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`); + } + } + catch (e) { + // The package might not exist. Don't re-throw the error here. + console.error('Tried to stat ' + binaryPath + ' but failed.'); + } + const findRequiresResult = (0, child_process_1.spawnSync)('/usr/lib/rpm/find-requires', { input: binaryPath + '\n' }); + if (findRequiresResult.status !== 0) { + throw new Error(`find-requires failed with exit code ${findRequiresResult.status}.\nstderr: ${findRequiresResult.stderr}`); + } + const requires = new Set(findRequiresResult.stdout.toString('utf-8').trimEnd().split('\n')); + return requires; +} diff --git a/build/linux/rpm/calculate-deps.ts b/build/linux/rpm/calculate-deps.ts new file mode 100644 index 00000000000..4be2200c018 --- /dev/null +++ b/build/linux/rpm/calculate-deps.ts @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { spawnSync } from 'child_process'; +import { constants, statSync } from 'fs'; +import { additionalDeps } from './dep-lists'; + +export function generatePackageDeps(files: string[]): Set[] { + const dependencies: Set[] = files.map(file => calculatePackageDeps(file)); + const additionalDepsSet = new Set(additionalDeps); + dependencies.push(additionalDepsSet); + return dependencies; +} + +// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/calculate_package_deps.py. +function calculatePackageDeps(binaryPath: string): Set { + try { + if (!(statSync(binaryPath).mode & constants.S_IXUSR)) { + throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`); + } + } catch (e) { + // The package might not exist. Don't re-throw the error here. + console.error('Tried to stat ' + binaryPath + ' but failed.'); + } + + const findRequiresResult = spawnSync('/usr/lib/rpm/find-requires', { input: binaryPath + '\n' }); + if (findRequiresResult.status !== 0) { + throw new Error(`find-requires failed with exit code ${findRequiresResult.status}.\nstderr: ${findRequiresResult.stderr}`); + } + + const requires = new Set(findRequiresResult.stdout.toString('utf-8').trimEnd().split('\n')); + return requires; +} diff --git a/build/linux/rpm/dep-lists.js b/build/linux/rpm/dep-lists.js index 02886a53b12..45c413f7934 100644 --- a/build/linux/rpm/dep-lists.js +++ b/build/linux/rpm/dep-lists.js @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.referenceGeneratedDepsByArch = exports.bundledDeps = exports.additionalDeps = void 0; +exports.referenceGeneratedDepsByArch = exports.additionalDeps = void 0; // Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/additional_deps // Additional dependencies not in the rpm find-requires output. exports.additionalDeps = [ @@ -17,18 +17,6 @@ exports.additionalDeps = [ 'libcurl.so.4()(64bit)', 'xdg-utils' // OS integration ]; -// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:chrome/installer/linux/BUILD.gn;l=64-80 -// and the Linux Archive build -// Shared library dependencies that we already bundle. -exports.bundledDeps = [ - 'libEGL.so', - 'libGLESv2.so', - 'libvulkan.so.1', - 'swiftshader_libEGL.so', - 'swiftshader_libGLESv2.so', - 'libvk_swiftshader.so', - 'libffmpeg.so' -]; exports.referenceGeneratedDepsByArch = { 'x86_64': [ 'ca-certificates', diff --git a/build/linux/rpm/dep-lists.ts b/build/linux/rpm/dep-lists.ts index 012755a04c5..d80c86416a6 100644 --- a/build/linux/rpm/dep-lists.ts +++ b/build/linux/rpm/dep-lists.ts @@ -16,19 +16,6 @@ export const additionalDeps = [ 'xdg-utils' // OS integration ]; -// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:chrome/installer/linux/BUILD.gn;l=64-80 -// and the Linux Archive build -// Shared library dependencies that we already bundle. -export const bundledDeps = [ - 'libEGL.so', - 'libGLESv2.so', - 'libvulkan.so.1', - 'swiftshader_libEGL.so', - 'swiftshader_libGLESv2.so', - 'libvk_swiftshader.so', - 'libffmpeg.so' -]; - export const referenceGeneratedDepsByArch = { 'x86_64': [ 'ca-certificates', diff --git a/build/linux/rpm/types.js b/build/linux/rpm/types.js index 56d4e6c56ce..9e140325075 100644 --- a/build/linux/rpm/types.js +++ b/build/linux/rpm/types.js @@ -4,3 +4,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); +exports.isRpmArchString = void 0; +function isRpmArchString(s) { + return ['x86_64', 'armv7hl', 'aarch64'].includes(s); +} +exports.isRpmArchString = isRpmArchString; diff --git a/build/linux/rpm/types.ts b/build/linux/rpm/types.ts index 84330949d1d..c6a01da1cf5 100644 --- a/build/linux/rpm/types.ts +++ b/build/linux/rpm/types.ts @@ -3,4 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export type ArchString = 'x86_64' | 'armv7hl' | 'aarch64'; +export type RpmArchString = 'x86_64' | 'armv7hl' | 'aarch64'; + +export function isRpmArchString(s: string): s is RpmArchString { + return ['x86_64', 'armv7hl', 'aarch64'].includes(s); +} diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index 5ca6a6005a4..57b57f58d4a 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -72,7 +72,7 @@ export interface ICommandHandler { #include(vs/editor/common/core/editOperation): ISingleEditOperation #include(vs/editor/common/core/wordHelper): IWordAtPosition #includeAll(vs/editor/common/model): IScrollEvent -#include(vs/editor/common/diff/diffComputer): IChange, ICharChange, ILineChange +#include(vs/editor/common/diff/smartLinesDiffComputer): IChange, ICharChange, ILineChange #include(vs/editor/common/core/dimension): IDimension #includeAll(vs/editor/common/editorCommon): IScrollEvent #includeAll(vs/editor/common/textModelEvents): diff --git a/build/npm/dirs.js b/build/npm/dirs.js index 35521822dc6..d77e0099290 100644 --- a/build/npm/dirs.js +++ b/build/npm/dirs.js @@ -28,6 +28,7 @@ exports.dirs = [ 'extensions/jake', 'extensions/json-language-features', 'extensions/json-language-features/server', + 'extensions/markdown-language-features/server', 'extensions/markdown-language-features', 'extensions/markdown-math', 'extensions/merge-conflict', diff --git a/build/npm/jsconfig.json b/build/npm/jsconfig.json index 41d18dab432..2b8f9ad1953 100644 --- a/build/npm/jsconfig.json +++ b/build/npm/jsconfig.json @@ -4,7 +4,7 @@ "lib": [ "ES2020" ], - "module": "node12", + "module": "node16", "checkJs": true, "noEmit": true } diff --git a/build/npm/update-all-grammars.mjs b/build/npm/update-all-grammars.mjs index 2da48570661..e0d34e42beb 100644 --- a/build/npm/update-all-grammars.mjs +++ b/build/npm/update-all-grammars.mjs @@ -6,7 +6,7 @@ import { spawn as _spawn } from 'child_process'; import { readdirSync, readFileSync } from 'fs'; import { join } from 'path'; -import url from 'url' +import url from 'url'; async function spawn(cmd, args, opts) { return new Promise((c, e) => { @@ -20,7 +20,7 @@ async function main() { for (const extension of readdirSync('extensions')) { try { - let packageJSON = JSON.parse(readFileSync(join('extensions', extension, 'package.json')).toString()); + const packageJSON = JSON.parse(readFileSync(join('extensions', extension, 'package.json')).toString()); if (!(packageJSON && packageJSON.scripts && packageJSON.scripts['update-grammar'])) { continue; } diff --git a/build/package.json b/build/package.json index b58f58be433..6d4464865f3 100644 --- a/build/package.json +++ b/build/package.json @@ -40,16 +40,13 @@ "@types/underscore": "^1.8.9", "@types/webpack": "^4.41.25", "@types/xml2js": "0.0.33", - "@typescript-eslint/experimental-utils": "^5.10.0", - "@typescript-eslint/parser": "^5.10.0", "@vscode/iconv-lite-umd": "0.7.0", - "applicationinsights": "1.4.2", "byline": "^5.0.0", "colors": "^1.4.0", "commander": "^7.0.0", "debug": "^4.3.2", "electron-osx-sign": "^0.4.16", - "esbuild": "^0.14.2", + "esbuild": "0.15.5", "extract-zip": "^2.0.1", "fs-extra": "^9.1.0", "got": "11.8.5", diff --git a/build/tsconfig.build.json b/build/tsconfig.build.json index 0a00f2d0f48..801c7735b06 100644 --- a/build/tsconfig.build.json +++ b/build/tsconfig.build.json @@ -7,5 +7,8 @@ }, "include": [ "**/*.ts" + ], + "exclude": [ + "lib/eslint-plugin-vscode/**/*" ] } diff --git a/build/win32/code.iss b/build/win32/code.iss index e96ca4bde77..192bbb0d2ba 100644 --- a/build/win32/code.iss +++ b/build/win32/code.iss @@ -1494,7 +1494,7 @@ begin Permissions := '/grant:r "*S-1-5-18:(OI)(CI)F" /grant:r "*S-1-5-32-544:(OI)(CI)F" /grant:r "*S-1-5-11:(OI)(CI)RX" /grant:r "*S-1-5-32-545:(OI)(CI)RX"'; #if "user" == InstallTarget - Permissions := Permissions + ' /grant:r "*S-1-3-0:(OI)(CI)F"'; + Permissions := Permissions + Format(' /grant:r "*S-1-3-0:(OI)(CI)F" /grant:r "%s:(OI)(CI)F"', [GetUserNameString()]); #endif Exec(ExpandConstant('{sys}\icacls.exe'), ExpandConstant('"{app}" /inheritancelevel:r ') + Permissions, '', SW_HIDE, ewWaitUntilTerminated, ResultCode); diff --git a/build/yarn.lock b/build/yarn.lock index bb6fcbcb482..bd5fcfac717 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -225,6 +225,11 @@ global-agent "^2.0.2" global-tunnel-ng "^2.7.1" +"@esbuild/linux-loong64@0.15.5": + version "0.15.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz#91aef76d332cdc7c8942b600fa2307f3387e6f82" + integrity sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A== + "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -232,27 +237,6 @@ dependencies: cross-spawn "^7.0.1" -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - "@opentelemetry/api@^1.0.1": version "1.0.3" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.0.3.tgz#13a12ae9e05c2a782f7b5e84c3cbfda4225eaf80" @@ -470,11 +454,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== -"@types/json-schema@^7.0.9": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - "@types/keyv@*": version "3.1.1" resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7" @@ -682,103 +661,6 @@ dependencies: "@types/node" "*" -"@typescript-eslint/experimental-utils@^5.10.0": - version "5.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.10.1.tgz#49fa5a7800ed08ea70aef14fccb14fbae85116ab" - integrity sha512-Ryeb8nkJa/1zKl8iujNtJC8tgj6PgaY0sDUnrTqbmC70nrKKkZaHfiRDTcqICmCSCEQyLQcJAoh0AukLaIaGTw== - dependencies: - "@typescript-eslint/utils" "5.10.1" - -"@typescript-eslint/parser@^5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.10.0.tgz#8f59e036f5f1cffc178cacbd5ccdd02aeb96c91c" - integrity sha512-pJB2CCeHWtwOAeIxv8CHVGJhI5FNyJAIpx5Pt72YkK3QfEzt6qAlXZuyaBmyfOdM62qU0rbxJzNToPTVeJGrQw== - dependencies: - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/typescript-estree" "5.10.0" - debug "^4.3.2" - -"@typescript-eslint/scope-manager@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.10.0.tgz#bb5d872e8b9e36203908595507fbc4d3105329cb" - integrity sha512-tgNgUgb4MhqK6DoKn3RBhyZ9aJga7EQrw+2/OiDk5hKf3pTVZWyqBi7ukP+Z0iEEDMF5FDa64LqODzlfE4O/Dg== - dependencies: - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/visitor-keys" "5.10.0" - -"@typescript-eslint/scope-manager@5.10.1": - version "5.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.10.1.tgz#f0539c73804d2423506db2475352a4dec36cd809" - integrity sha512-Lyvi559Gvpn94k7+ElXNMEnXu/iundV5uFmCUNnftbFrUbAJ1WBoaGgkbOBm07jVZa682oaBU37ao/NGGX4ZDg== - dependencies: - "@typescript-eslint/types" "5.10.1" - "@typescript-eslint/visitor-keys" "5.10.1" - -"@typescript-eslint/types@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.0.tgz#beb3cb345076f5b088afe996d57bcd1dfddaa75c" - integrity sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ== - -"@typescript-eslint/types@5.10.1": - version "5.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.1.tgz#dca9bd4cb8c067fc85304a31f38ec4766ba2d1ea" - integrity sha512-ZvxQ2QMy49bIIBpTqFiOenucqUyjTQ0WNLhBM6X1fh1NNlYAC6Kxsx8bRTY3jdYsYg44a0Z/uEgQkohbR0H87Q== - -"@typescript-eslint/typescript-estree@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz#4be24a3dea0f930bb1397c46187d0efdd955a224" - integrity sha512-x+7e5IqfwLwsxTdliHRtlIYkgdtYXzE0CkFeV6ytAqq431ZyxCFzNMNR5sr3WOlIG/ihVZr9K/y71VHTF/DUQA== - dependencies: - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/visitor-keys" "5.10.0" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/typescript-estree@5.10.1": - version "5.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.1.tgz#b268e67be0553f8790ba3fe87113282977adda15" - integrity sha512-PwIGnH7jIueXv4opcwEbVGDATjGPO1dx9RkUl5LlHDSe+FXxPwFL5W/qYd5/NHr7f6lo/vvTrAzd0KlQtRusJQ== - dependencies: - "@typescript-eslint/types" "5.10.1" - "@typescript-eslint/visitor-keys" "5.10.1" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.10.1": - version "5.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.10.1.tgz#fa682a33af47080ba2c4368ee0ad2128213a1196" - integrity sha512-RRmlITiUbLuTRtn/gcPRi4202niF+q7ylFLCKu4c+O/PcpRvZ/nAUwQ2G00bZgpWkhrNLNnvhZLbDn8Ml0qsQw== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.10.1" - "@typescript-eslint/types" "5.10.1" - "@typescript-eslint/typescript-estree" "5.10.1" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/visitor-keys@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz#770215497ad67cd15a572b52089991d5dfe06281" - integrity sha512-GMxj0K1uyrFLPKASLmZzCuSddmjZVbVj3Ouy5QVuIGKZopxvOr24JsS7gruz6C3GExE01mublZ3mIBOaon9zuQ== - dependencies: - "@typescript-eslint/types" "5.10.0" - eslint-visitor-keys "^3.0.0" - -"@typescript-eslint/visitor-keys@5.10.1": - version "5.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.1.tgz#29102de692f59d7d34ecc457ed59ab5fc558010b" - integrity sha512-NjQ0Xinhy9IL979tpoTRuLKxMc0zJC7QVSdeerXs2/QvOy2yRkzX5dRb10X5woNUdJgU8G3nYRDlI33sq1K4YQ== - dependencies: - "@typescript-eslint/types" "5.10.1" - eslint-visitor-keys "^3.0.0" - "@vscode/iconv-lite-umd@0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@vscode/iconv-lite-umd/-/iconv-lite-umd-0.7.0.tgz#d2f1e0664ee6036408f9743fee264ea0699b0e48" @@ -847,16 +729,6 @@ anymatch@^3.0.0, anymatch@^3.1.1, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -applicationinsights@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.4.2.tgz#2f25f7a3f3e5bf0ab4486b63e42a48a9ec321d52" - integrity sha512-1wE37G9zEMZTsPJVQ8BDrQtsGgG3DGMActLHwPAF8TYHAXkfqqpeZYCH0XV4lUZ7H4MffRMwN2Ln2nEtUmT8HQ== - dependencies: - cls-hooked "^4.2.2" - continuation-local-storage "^3.2.1" - diagnostic-channel "0.2.0" - diagnostic-channel-publishers "^0.3.3" - aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -887,11 +759,6 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - asar@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/asar/-/asar-3.0.3.tgz#1fef03c2d6d2de0cbad138788e4f7ae03b129c7b" @@ -909,21 +776,6 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -async-hook-jl@^1.7.6: - version "1.7.6" - resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" - integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== - dependencies: - stack-chain "^1.3.7" - -async-listener@^0.6.0: - version "0.6.10" - resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc" - integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw== - dependencies: - semver "^5.3.0" - shimmer "^1.1.0" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -996,7 +848,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^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== @@ -1185,15 +1037,6 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" -cls-hooked@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" - integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== - dependencies: - async-hook-jl "^1.7.6" - emitter-listener "^1.0.1" - semver "^5.4.1" - 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" @@ -1290,14 +1133,6 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -continuation-local-storage@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb" - integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA== - dependencies: - async-listener "^0.6.0" - emitter-listener "^1.1.1" - core-js@^3.6.5: version "3.15.2" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.15.2.tgz#740660d2ff55ef34ce664d7e2455119c5bdd3d61" @@ -1427,18 +1262,6 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== -diagnostic-channel-publishers@^0.3.3: - version "0.3.5" - resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.5.tgz#a84a05fd6cc1d7619fdd17791c17e540119a7536" - integrity sha512-AOIjw4T7Nxl0G2BoBPhkQ6i7T4bUd9+xvdYizwvG7vVAM1dvr+SDrcUudlmzwH0kbEwdR2V1EcnKT0wAeYLQNQ== - -diagnostic-channel@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17" - integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc= - dependencies: - semver "^5.3.0" - dir-compare@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/dir-compare/-/dir-compare-2.4.0.tgz#785c41dc5f645b34343a4eafc50b79bac7f11631" @@ -1449,13 +1272,6 @@ dir-compare@^2.4.0: commander "2.9.0" minimatch "3.0.4" -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - dom-serializer@^1.0.1, dom-serializer@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" @@ -1510,13 +1326,6 @@ electron-osx-sign@^0.4.16: minimist "^1.2.0" plist "^3.0.1" -emitter-listener@^1.0.1, emitter-listener@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -1554,113 +1363,132 @@ es6-error@^4.1.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild-android-arm64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz#256b7cf2f9d382a2a92a4ff4e13187587c9b7c6a" - integrity sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw== +esbuild-android-64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz#3c7b2f2a59017dab3f2c0356188a8dd9cbdc91c8" + integrity sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg== -esbuild-darwin-64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz#891a59ce6bc3aded0265f982469b3eb9571b92f8" - integrity sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA== +esbuild-android-arm64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz#e301db818c5a67b786bf3bb7320e414ac0fcf193" + integrity sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg== -esbuild-darwin-arm64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz#ab834fffa9c612b2901ca1e77e4695d4d8aa63a2" - integrity sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A== +esbuild-darwin-64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz#11726de5d0bf5960b92421ef433e35871c091f8d" + integrity sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ== -esbuild-freebsd-64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz#f7fc87a83f02de27d5a48472571efa1a432ae86d" - integrity sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ== +esbuild-darwin-arm64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz#ad89dafebb3613fd374f5a245bb0ce4132413997" + integrity sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg== -esbuild-freebsd-arm64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz#bc8758420431106751f3180293cac0b5bc4ce2ee" - integrity sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ== +esbuild-freebsd-64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz#6bfb52b4a0d29c965aa833e04126e95173289c8a" + integrity sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA== -esbuild-linux-32@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz#0cc2dcd816d6d66e255bc7aeac139b1d04246812" - integrity sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ== +esbuild-freebsd-arm64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz#38a3fed8c6398072f9914856c7c3e3444f9ef4dd" + integrity sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w== -esbuild-linux-64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz#c790f739aa75b15c153609ea3457153fbe4db93d" - integrity sha512-4bzMS2dNxOJoFIiHId4w+tqQzdnsch71JJV1qZnbnErSFWcR9lRgpSqWnTTFtv6XM+MvltRzSXC5wQ7AEBY6Hg== +esbuild-linux-32@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz#942dc70127f0c0a7ea91111baf2806e61fc81b32" + integrity sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ== -esbuild-linux-arm64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz#96858a1f89ad30274dec780d0e3dd8b5691c6b0c" - integrity sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww== +esbuild-linux-64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz#6d748564492d5daaa7e62420862c31ac3a44aed9" + integrity sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg== -esbuild-linux-arm@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz#03e193225afa9b1215d2ec6efe8edf0c03eeed6f" - integrity sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ== +esbuild-linux-arm64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz#28cd899beb2d2b0a3870fd44f4526835089a318d" + integrity sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA== -esbuild-linux-mips64le@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz#972f218d2cb5125237376d40ad60a6e5356a782c" - integrity sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ== +esbuild-linux-arm@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz#6441c256225564d8794fdef5b0a69bc1a43051b5" + integrity sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q== -esbuild-linux-ppc64le@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz#20b71622ac09142b0e523f633af0829def7fed6b" - integrity sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA== +esbuild-linux-mips64le@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz#d4927f817290eaffc062446896b2a553f0e11981" + integrity sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ== -esbuild-netbsd-64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz#dbd6a25117902ef67aa11d8779dd9c6bca7fbe82" - integrity sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw== +esbuild-linux-ppc64le@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz#b6d660dc6d5295f89ac51c675f1a2f639e2fb474" + integrity sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw== -esbuild-openbsd-64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz#3c5f199eed459b2f88865548394c0b77383d9ca4" - integrity sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q== +esbuild-linux-riscv64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz#2801bf18414dc3d3ad58d1ea83084f00d9d84896" + integrity sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA== -esbuild-sunos-64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz#900a681db6b76c6a7f60fc28d2bfe5b11698641c" - integrity sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow== +esbuild-linux-s390x@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz#12a634ae6d3384cacc2b8f4201047deafe596eae" + integrity sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ== -esbuild-windows-32@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz#61e0ba5bd95b277a55d2b997ac4c04dfe2559220" - integrity sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ== +esbuild-netbsd-64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz#951bbf87600512dfcfbe3b8d9d117d684d26c1b8" + integrity sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w== -esbuild-windows-64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz#6ab59ef721ff75c682a1c8ae0570dabb637abddb" - integrity sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg== +esbuild-openbsd-64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz#26705b61961d525d79a772232e8b8f211fdbb035" + integrity sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA== -esbuild-windows-arm64@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz#aca2a4f83d2f0d1592ad4be832ed0045fc888cda" - integrity sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA== +esbuild-sunos-64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz#d794da1ae60e6e2f6194c44d7b3c66bf66c7a141" + integrity sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA== -esbuild@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.2.tgz#9c1e1a652549cc33e44885eea42ea2cc6267edc2" - integrity sha512-l076A6o/PIgcyM24s0dWmDI/b8RQf41uWoJu9I0M71CtW/YSw5T5NUeXxs5lo2tFQD+O4CW4nBHJXx3OY5NpXg== +esbuild-windows-32@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz#0670326903f421424be86bc03b7f7b3ff86a9db7" + integrity sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg== + +esbuild-windows-64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz#64f32acb7341f3f0a4d10e8ff1998c2d1ebfc0a9" + integrity sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw== + +esbuild-windows-arm64@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz#4fe7f333ce22a922906b10233c62171673a3854b" + integrity sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA== + +esbuild@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.5.tgz#5effd05666f621d4ff2fe2c76a67c198292193ff" + integrity sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg== optionalDependencies: - esbuild-android-arm64 "0.14.2" - esbuild-darwin-64 "0.14.2" - esbuild-darwin-arm64 "0.14.2" - esbuild-freebsd-64 "0.14.2" - esbuild-freebsd-arm64 "0.14.2" - esbuild-linux-32 "0.14.2" - esbuild-linux-64 "0.14.2" - esbuild-linux-arm "0.14.2" - esbuild-linux-arm64 "0.14.2" - esbuild-linux-mips64le "0.14.2" - esbuild-linux-ppc64le "0.14.2" - esbuild-netbsd-64 "0.14.2" - esbuild-openbsd-64 "0.14.2" - esbuild-sunos-64 "0.14.2" - esbuild-windows-32 "0.14.2" - esbuild-windows-64 "0.14.2" - esbuild-windows-arm64 "0.14.2" + "@esbuild/linux-loong64" "0.15.5" + esbuild-android-64 "0.15.5" + esbuild-android-arm64 "0.15.5" + esbuild-darwin-64 "0.15.5" + esbuild-darwin-arm64 "0.15.5" + esbuild-freebsd-64 "0.15.5" + esbuild-freebsd-arm64 "0.15.5" + esbuild-linux-32 "0.15.5" + esbuild-linux-64 "0.15.5" + esbuild-linux-arm "0.15.5" + esbuild-linux-arm64 "0.15.5" + esbuild-linux-mips64le "0.15.5" + esbuild-linux-ppc64le "0.15.5" + esbuild-linux-riscv64 "0.15.5" + esbuild-linux-s390x "0.15.5" + esbuild-netbsd-64 "0.15.5" + esbuild-openbsd-64 "0.15.5" + esbuild-sunos-64 "0.15.5" + esbuild-windows-32 "0.15.5" + esbuild-windows-64 "0.15.5" + esbuild-windows-arm64 "0.15.5" escape-string-regexp@^1.0.5: version "1.0.5" @@ -1672,48 +1500,6 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1" - integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - events@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" @@ -1753,29 +1539,11 @@ fancy-log@^1.3.3: parse-node-version "^1.0.0" time-stamp "^1.0.0" -fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -1901,7 +1669,7 @@ github-from-package@0.0.0: resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= -glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.0: +glob-parent@^5.1.1, glob-parent@~5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -1962,18 +1730,6 @@ globalthis@^1.0.1: dependencies: define-properties "^1.1.3" -globby@^11.0.4: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - got@11.8.5: version "11.8.5" resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" @@ -2125,11 +1881,6 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -2191,7 +1942,7 @@ is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" -is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -2473,19 +2224,6 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - mime-db@1.45.0: version "1.45.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" @@ -2739,11 +2477,6 @@ path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -2754,7 +2487,7 @@ picomatch@^2.0.4: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== -picomatch@^2.2.1, picomatch@^2.2.3: +picomatch@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -2870,11 +2603,6 @@ qs@^6.9.1: dependencies: side-channel "^1.0.4" -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - quick-lru@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" @@ -2955,11 +2683,6 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - rimraf@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -2979,13 +2702,6 @@ roarr@^2.15.3: semver-compare "^1.0.0" sprintf-js "^1.1.2" -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -3011,7 +2727,7 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -semver@^5.1.0, semver@^5.3.0: +semver@^5.1.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== @@ -3033,13 +2749,6 @@ semver@^7.3.2: dependencies: lru-cache "^6.0.0" -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" @@ -3064,11 +2773,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shimmer@^1.1.0, shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -3097,11 +2801,6 @@ simple-get@^3.0.3: once "^1.3.1" simple-concat "^1.0.0" -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -3122,11 +2821,6 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -stack-chain@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= - stoppable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" @@ -3331,11 +3025,6 @@ tslib@^1.10.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^1.8.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== - tslib@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" @@ -3346,13 +3035,6 @@ tslib@^2.2.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" diff --git a/cglicenses.json b/cglicenses.json index 4ce1e015e46..f80a3fac7fc 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -173,5 +173,52 @@ "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", "SOFTWARE" ] + }, + { + // Reason: This product includes AVC coding technology. MPEG LA LLC requires this notice. + "name": "H.264/AVC Video Standard", + "fullLicenseText": [ + "This product is licensed under the AVC patent portfolio license for the personal", + "and non-commercial use of a consumer to (i) encode video in compliance with the AVC standard (\"AVC VIDEO\")", + "and/or (ii) decode AVC video that was encoded by a consumer", + "engaged in a personal and non-commercial activity and/or was obtained from a video provider", + "licensed to provide AVC video. No license is granted or shall be implied for any other use.", + "Additional information may be obtained from MPEG LA LLC. See http://www.MPEGLA.COM.", + "", + "For clarification purposes, this notice does not limit or inhibit the use of the product", + "for normal business uses that are personal to that business which do not include", + "(i) redistribution of the product to third parties, or", + "(ii) creation of content with AVC Standard compliant technologies for distribution to third parties." + ] + }, + { + // Reason: Missing license file + "name": "@tokenizer/token", + "fullLicenseText": [ + "(The MIT License)", + "", + "Copyright (c) 2020 Borewit", + "", + "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." + ] + }, + { + // Reason: Missing license file + "name": "readable-web-to-node-stream", + "fullLicenseText": [ + "(The MIT License)", + "", + "Copyright (c) 2019 Borewit", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] } ] diff --git a/cgmanifest.json b/cgmanifest.json index 932f6d682aa..3d2387b7ee9 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "chromium", "repositoryUrl": "https://chromium.googlesource.com/chromium/src", - "commitHash": "59f4a82f7cf9fd0397aa7bf0273bf5b62433c5da" + "commitHash": "16e28102fdf876ce6d136674ba66343ede07441f" } }, "licenseDetail": [ @@ -40,7 +40,449 @@ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ], "isOnlyProductionDependency": true, - "version": "100.0.4896.160" + "version": "102.0.5005.167" + }, + { + "component": { + "type": "git", + "git": { + "name": "ffmpeg", + "repositoryUrl": "https://chromium.googlesource.com/chromium/third_party/ffmpeg", + "commitHash": "5cd95cdf972ad92c38a4ea2d059ac9d6167302ca" + } + }, + "isOnlyProductionDependency": true, + "license": "LGPL-2.1+", + "version": "4.4.git", + "licenseDetail": [ + " GNU LESSER GENERAL PUBLIC LICENSE", + " Version 2.1, February 1999", + " Copyright (C) 1991, 1999 Free Software Foundation, Inc.", + " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA", + " Everyone is permitted to copy and distribute verbatim copies", + " of this license document, but changing it is not allowed.", + "[This is the first released version of the Lesser GPL. It also counts", + " as the successor of the GNU Library Public License, version 2, hence", + " the version number 2.1.]", + " Preamble", + " The licenses for most software are designed to take away your", + "freedom to share and change it. By contrast, the GNU General Public", + "Licenses are intended to guarantee your freedom to share and change", + "free software--to make sure the software is free for all its users.", + " This license, the Lesser General Public License, applies to some", + "specially designated software packages--typically libraries--of the", + "Free Software Foundation and other authors who decide to use it. You", + "can use it too, but we suggest you first think carefully about whether", + "this license or the ordinary General Public License is the better", + "strategy to use in any particular case, based on the explanations below.", + " When we speak of free software, we are referring to freedom of use,", + "not price. Our General Public Licenses are designed to make sure that", + "you have the freedom to distribute copies of free software (and charge", + "for this service if you wish); that you receive source code or can get", + "it if you want it; that you can change the software and use pieces of", + "it in new free programs; and that you are informed that you can do", + "these things.", + " To protect your rights, we need to make restrictions that forbid", + "distributors to deny you these rights or to ask you to surrender these", + "rights. These restrictions translate to certain responsibilities for", + "you if you distribute copies of the library or if you modify it.", + " For example, if you distribute copies of the library, whether gratis", + "or for a fee, you must give the recipients all the rights that we gave", + "you. You must make sure that they, too, receive or can get the source", + "code. If you link other code with the library, you must provide", + "complete object files to the recipients, so that they can relink them", + "with the library after making changes to the library and recompiling", + "it. And you must show them these terms so they know their rights.", + " We protect your rights with a two-step method: (1) we copyright the", + "library, and (2) we offer you this license, which gives you legal", + "permission to copy, distribute and/or modify the library.", + " To protect each distributor, we want to make it very clear that", + "there is no warranty for the free library. Also, if the library is", + "modified by someone else and passed on, the recipients should know", + "that what they have is not the original version, so that the original", + "author's reputation will not be affected by problems that might be", + "introduced by others.", + "", + " Finally, software patents pose a constant threat to the existence of", + "any free program. We wish to make sure that a company cannot", + "effectively restrict the users of a free program by obtaining a", + "restrictive license from a patent holder. Therefore, we insist that", + "any patent license obtained for a version of the library must be", + "consistent with the full freedom of use specified in this license.", + " Most GNU software, including some libraries, is covered by the", + "ordinary GNU General Public License. This license, the GNU Lesser", + "General Public License, applies to certain designated libraries, and", + "is quite different from the ordinary General Public License. We use", + "this license for certain libraries in order to permit linking those", + "libraries into non-free programs.", + " When a program is linked with a library, whether statically or using", + "a shared library, the combination of the two is legally speaking a", + "combined work, a derivative of the original library. The ordinary", + "General Public License therefore permits such linking only if the", + "entire combination fits its criteria of freedom. The Lesser General", + "Public License permits more lax criteria for linking other code with", + "the library.", + " We call this license the \"Lesser\" General Public License because it", + "does Less to protect the user's freedom than the ordinary General", + "Public License. It also provides other free software developers Less", + "of an advantage over competing non-free programs. These disadvantages", + "are the reason we use the ordinary General Public License for many", + "libraries. However, the Lesser license provides advantages in certain", + "special circumstances.", + " For example, on rare occasions, there may be a special need to", + "encourage the widest possible use of a certain library, so that it becomes", + "a de-facto standard. To achieve this, non-free programs must be", + "allowed to use the library. A more frequent case is that a free", + "library does the same job as widely used non-free libraries. In this", + "case, there is little to gain by limiting the free library to free", + "software only, so we use the Lesser General Public License.", + " In other cases, permission to use a particular library in non-free", + "programs enables a greater number of people to use a large body of", + "free software. For example, permission to use the GNU C Library in", + "non-free programs enables many more people to use the whole GNU", + "operating system, as well as its variant, the GNU/Linux operating", + "system.", + " Although the Lesser General Public License is Less protective of the", + "users' freedom, it does ensure that the user of a program that is", + "linked with the Library has the freedom and the wherewithal to run", + "that program using a modified version of the Library.", + " The precise terms and conditions for copying, distribution and", + "modification follow. Pay close attention to the difference between a", + "\"work based on the library\" and a \"work that uses the library\". The", + "former contains code derived from the library, whereas the latter must", + "be combined with the library in order to run.", + "", + " GNU LESSER GENERAL PUBLIC LICENSE", + " TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION", + " 0. This License Agreement applies to any software library or other", + "program which contains a notice placed by the copyright holder or", + "other authorized party saying it may be distributed under the terms of", + "this Lesser General Public License (also called \"this License\").", + "Each licensee is addressed as \"you\".", + " A \"library\" means a collection of software functions and/or data", + "prepared so as to be conveniently linked with application programs", + "(which use some of those functions and data) to form executables.", + " The \"Library\", below, refers to any such software library or work", + "which has been distributed under these terms. A \"work based on the", + "Library\" means either the Library or any derivative work under", + "copyright law: that is to say, a work containing the Library or a", + "portion of it, either verbatim or with modifications and/or translated", + "straightforwardly into another language. (Hereinafter, translation is", + "included without limitation in the term \"modification\".)", + " \"Source code\" for a work means the preferred form of the work for", + "making modifications to it. For a library, complete source code means", + "all the source code for all modules it contains, plus any associated", + "interface definition files, plus the scripts used to control compilation", + "and installation of the library.", + " Activities other than copying, distribution and modification are not", + "covered by this License; they are outside its scope. The act of", + "running a program using the Library is not restricted, and output from", + "such a program is covered only if its contents constitute a work based", + "on the Library (independent of the use of the Library in a tool for", + "writing it). Whether that is true depends on what the Library does", + "and what the program that uses the Library does.", + " 1. You may copy and distribute verbatim copies of the Library's", + "complete source code as you receive it, in any medium, provided that", + "you conspicuously and appropriately publish on each copy an", + "appropriate copyright notice and disclaimer of warranty; keep intact", + "all the notices that refer to this License and to the absence of any", + "warranty; and distribute a copy of this License along with the", + "Library.", + " You may charge a fee for the physical act of transferring a copy,", + "and you may at your option offer warranty protection in exchange for a", + "fee.", + "", + " 2. You may modify your copy or copies of the Library or any portion", + "of it, thus forming a work based on the Library, and copy and", + "distribute such modifications or work under the terms of Section 1", + "above, provided that you also meet all of these conditions:", + " a) The modified work must itself be a software library.", + " b) You must cause the files modified to carry prominent notices", + " stating that you changed the files and the date of any change.", + " c) You must cause the whole of the work to be licensed at no", + " charge to all third parties under the terms of this License.", + " d) If a facility in the modified Library refers to a function or a", + " table of data to be supplied by an application program that uses", + " the facility, other than as an argument passed when the facility", + " is invoked, then you must make a good faith effort to ensure that,", + " in the event an application does not supply such function or", + " table, the facility still operates, and performs whatever part of", + " its purpose remains meaningful.", + " (For example, a function in a library to compute square roots has", + " a purpose that is entirely well-defined independent of the", + " application. Therefore, Subsection 2d requires that any", + " application-supplied function or table used by this function must", + " be optional: if the application does not supply it, the square", + " root function must still compute square roots.)", + "These requirements apply to the modified work as a whole. If", + "identifiable sections of that work are not derived from the Library,", + "and can be reasonably considered independent and separate works in", + "themselves, then this License, and its terms, do not apply to those", + "sections when you distribute them as separate works. But when you", + "distribute the same sections as part of a whole which is a work based", + "on the Library, the distribution of the whole must be on the terms of", + "this License, whose permissions for other licensees extend to the", + "entire whole, and thus to each and every part regardless of who wrote", + "it.", + "Thus, it is not the intent of this section to claim rights or contest", + "your rights to work written entirely by you; rather, the intent is to", + "exercise the right to control the distribution of derivative or", + "collective works based on the Library.", + "In addition, mere aggregation of another work not based on the Library", + "with the Library (or with a work based on the Library) on a volume of", + "a storage or distribution medium does not bring the other work under", + "the scope of this License.", + " 3. You may opt to apply the terms of the ordinary GNU General Public", + "License instead of this License to a given copy of the Library. To do", + "this, you must alter all the notices that refer to this License, so", + "that they refer to the ordinary GNU General Public License, version 2,", + "instead of to this License. (If a newer version than version 2 of the", + "ordinary GNU General Public License has appeared, then you can specify", + "that version instead if you wish.) Do not make any other change in", + "these notices.", + "", + " Once this change is made in a given copy, it is irreversible for", + "that copy, so the ordinary GNU General Public License applies to all", + "subsequent copies and derivative works made from that copy.", + " This option is useful when you wish to copy part of the code of", + "the Library into a program that is not a library.", + " 4. You may copy and distribute the Library (or a portion or", + "derivative of it, under Section 2) in object code or executable form", + "under the terms of Sections 1 and 2 above provided that you accompany", + "it with the complete corresponding machine-readable source code, which", + "must be distributed under the terms of Sections 1 and 2 above on a", + "medium customarily used for software interchange.", + " If distribution of object code is made by offering access to copy", + "from a designated place, then offering equivalent access to copy the", + "source code from the same place satisfies the requirement to", + "distribute the source code, even though third parties are not", + "compelled to copy the source along with the object code.", + " 5. A program that contains no derivative of any portion of the", + "Library, but is designed to work with the Library by being compiled or", + "linked with it, is called a \"work that uses the Library\". Such a", + "work, in isolation, is not a derivative work of the Library, and", + "therefore falls outside the scope of this License.", + " However, linking a \"work that uses the Library\" with the Library", + "creates an executable that is a derivative of the Library (because it", + "contains portions of the Library), rather than a \"work that uses the", + "library\". The executable is therefore covered by this License.", + "Section 6 states terms for distribution of such executables.", + " When a \"work that uses the Library\" uses material from a header file", + "that is part of the Library, the object code for the work may be a", + "derivative work of the Library even though the source code is not.", + "Whether this is true is especially significant if the work can be", + "linked without the Library, or if the work is itself a library. The", + "threshold for this to be true is not precisely defined by law.", + " If such an object file uses only numerical parameters, data", + "structure layouts and accessors, and small macros and small inline", + "functions (ten lines or less in length), then the use of the object", + "file is unrestricted, regardless of whether it is legally a derivative", + "work. (Executables containing this object code plus portions of the", + "Library will still fall under Section 6.)", + " Otherwise, if the work is a derivative of the Library, you may", + "distribute the object code for the work under the terms of Section 6.", + "Any executables containing that work also fall under Section 6,", + "whether or not they are linked directly with the Library itself.", + "", + " 6. As an exception to the Sections above, you may also combine or", + "link a \"work that uses the Library\" with the Library to produce a", + "work containing portions of the Library, and distribute that work", + "under terms of your choice, provided that the terms permit", + "modification of the work for the customer's own use and reverse", + "engineering for debugging such modifications.", + " You must give prominent notice with each copy of the work that the", + "Library is used in it and that the Library and its use are covered by", + "this License. You must supply a copy of this License. If the work", + "during execution displays copyright notices, you must include the", + "copyright notice for the Library among them, as well as a reference", + "directing the user to the copy of this License. Also, you must do one", + "of these things:", + " a) Accompany the work with the complete corresponding", + " machine-readable source code for the Library including whatever", + " changes were used in the work (which must be distributed under", + " Sections 1 and 2 above); and, if the work is an executable linked", + " with the Library, with the complete machine-readable \"work that", + " uses the Library\", as object code and/or source code, so that the", + " user can modify the Library and then relink to produce a modified", + " executable containing the modified Library. (It is understood", + " that the user who changes the contents of definitions files in the", + " Library will not necessarily be able to recompile the application", + " to use the modified definitions.)", + " b) Use a suitable shared library mechanism for linking with the", + " Library. A suitable mechanism is one that (1) uses at run time a", + " copy of the library already present on the user's computer system,", + " rather than copying library functions into the executable, and (2)", + " will operate properly with a modified version of the library, if", + " the user installs one, as long as the modified version is", + " interface-compatible with the version that the work was made with.", + " c) Accompany the work with a written offer, valid for at", + " least three years, to give the same user the materials", + " specified in Subsection 6a, above, for a charge no more", + " than the cost of performing this distribution.", + " d) If distribution of the work is made by offering access to copy", + " from a designated place, offer equivalent access to copy the above", + " specified materials from the same place.", + " e) Verify that the user has already received a copy of these", + " materials or that you have already sent this user a copy.", + " For an executable, the required form of the \"work that uses the", + "Library\" must include any data and utility programs needed for", + "reproducing the executable from it. However, as a special exception,", + "the materials to be distributed need not include anything that is", + "normally distributed (in either source or binary form) with the major", + "components (compiler, kernel, and so on) of the operating system on", + "which the executable runs, unless that component itself accompanies", + "the executable.", + " It may happen that this requirement contradicts the license", + "restrictions of other proprietary libraries that do not normally", + "accompany the operating system. Such a contradiction means you cannot", + "use both them and the Library together in an executable that you", + "distribute.", + "", + " 7. You may place library facilities that are a work based on the", + "Library side-by-side in a single library together with other library", + "facilities not covered by this License, and distribute such a combined", + "library, provided that the separate distribution of the work based on", + "the Library and of the other library facilities is otherwise", + "permitted, and provided that you do these two things:", + " a) Accompany the combined library with a copy of the same work", + " based on the Library, uncombined with any other library", + " facilities. This must be distributed under the terms of the", + " Sections above.", + " b) Give prominent notice with the combined library of the fact", + " that part of it is a work based on the Library, and explaining", + " where to find the accompanying uncombined form of the same work.", + " 8. You may not copy, modify, sublicense, link with, or distribute", + "the Library except as expressly provided under this License. Any", + "attempt otherwise to copy, modify, sublicense, link with, or", + "distribute the Library is void, and will automatically terminate your", + "rights under this License. However, parties who have received copies,", + "or rights, from you under this License will not have their licenses", + "terminated so long as such parties remain in full compliance.", + " 9. You are not required to accept this License, since you have not", + "signed it. However, nothing else grants you permission to modify or", + "distribute the Library or its derivative works. These actions are", + "prohibited by law if you do not accept this License. Therefore, by", + "modifying or distributing the Library (or any work based on the", + "Library), you indicate your acceptance of this License to do so, and", + "all its terms and conditions for copying, distributing or modifying", + "the Library or works based on it.", + " 10. Each time you redistribute the Library (or any work based on the", + "Library), the recipient automatically receives a license from the", + "original licensor to copy, distribute, link with or modify the Library", + "subject to these terms and conditions. You may not impose any further", + "restrictions on the recipients' exercise of the rights granted herein.", + "You are not responsible for enforcing compliance by third parties with", + "this License.", + "", + " 11. If, as a consequence of a court judgment or allegation of patent", + "infringement or for any other reason (not limited to patent issues),", + "conditions are imposed on you (whether by court order, agreement or", + "otherwise) that contradict the conditions of this License, they do not", + "excuse you from the conditions of this License. If you cannot", + "distribute so as to satisfy simultaneously your obligations under this", + "License and any other pertinent obligations, then as a consequence you", + "may not distribute the Library at all. For example, if a patent", + "license would not permit royalty-free redistribution of the Library by", + "all those who receive copies directly or indirectly through you, then", + "the only way you could satisfy both it and this License would be to", + "refrain entirely from distribution of the Library.", + "If any portion of this section is held invalid or unenforceable under any", + "particular circumstance, the balance of the section is intended to apply,", + "and the section as a whole is intended to apply in other circumstances.", + "It is not the purpose of this section to induce you to infringe any", + "patents or other property right claims or to contest validity of any", + "such claims; this section has the sole purpose of protecting the", + "integrity of the free software distribution system which is", + "implemented by public license practices. Many people have made", + "generous contributions to the wide range of software distributed", + "through that system in reliance on consistent application of that", + "system; it is up to the author/donor to decide if he or she is willing", + "to distribute software through any other system and a licensee cannot", + "impose that choice.", + "This section is intended to make thoroughly clear what is believed to", + "be a consequence of the rest of this License.", + " 12. If the distribution and/or use of the Library is restricted in", + "certain countries either by patents or by copyrighted interfaces, the", + "original copyright holder who places the Library under this License may add", + "an explicit geographical distribution limitation excluding those countries,", + "so that distribution is permitted only in or among countries not thus", + "excluded. In such case, this License incorporates the limitation as if", + "written in the body of this License.", + " 13. The Free Software Foundation may publish revised and/or new", + "versions of the Lesser General Public License from time to time.", + "Such new versions will be similar in spirit to the present version,", + "but may differ in detail to address new problems or concerns.", + "Each version is given a distinguishing version number. If the Library", + "specifies a version number of this License which applies to it and", + "\"any later version\", you have the option of following the terms and", + "conditions either of that version or of any later version published by", + "the Free Software Foundation. If the Library does not specify a", + "license version number, you may choose any version ever published by", + "the Free Software Foundation.", + "", + " 14. If you wish to incorporate parts of the Library into other free", + "programs whose distribution conditions are incompatible with these,", + "write to the author to ask for permission. For software which is", + "copyrighted by the Free Software Foundation, write to the Free", + "Software Foundation; we sometimes make exceptions for this. Our", + "decision will be guided by the two goals of preserving the free status", + "of all derivatives of our free software and of promoting the sharing", + "and reuse of software generally.", + " NO WARRANTY", + " 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO", + "WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.", + "EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR", + "OTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY", + "KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE", + "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR", + "PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE", + "LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME", + "THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.", + " 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN", + "WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY", + "AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU", + "FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR", + "CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE", + "LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING", + "RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A", + "FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF", + "SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH", + "DAMAGES.", + " END OF TERMS AND CONDITIONS", + "", + " How to Apply These Terms to Your New Libraries", + " If you develop a new library, and you want it to be of the greatest", + "possible use to the public, we recommend making it free software that", + "everyone can redistribute and change. You can do so by permitting", + "redistribution under these terms (or, alternatively, under the terms of the", + "ordinary General Public License).", + " To apply these terms, attach the following notices to the library. It is", + "safest to attach them to the start of each source file to most effectively", + "convey the exclusion of warranty; and each file should have at least the", + "\"copyright\" line and a pointer to where the full notice is found.", + " ", + " Copyright (C) ", + " This library is free software; you can redistribute it and/or", + " modify it under the terms of the GNU Lesser General Public", + " License as published by the Free Software Foundation; either", + " version 2.1 of the License, or (at your option) any later version.", + " This library is distributed in the hope that it will be useful,", + " but WITHOUT ANY WARRANTY; without even the implied warranty of", + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU", + " Lesser General Public License for more details.", + " You should have received a copy of the GNU Lesser General Public", + " License along with this library; if not, write to the Free Software", + " Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA", + "Also add information on how to contact you by electronic and paper mail.", + "You should also get your employer (if you work as a programmer) or your", + "school, if any, to sign a \"copyright disclaimer\" for the library, if", + "necessary. Here is a sample; alter the names:", + " Yoyodyne, Inc., hereby disclaims all copyright interest in the", + " library `Frob' (a library for tweaking knobs) written by James Random Hacker.", + " , 1 April 1990", + " Ty Coon, President of Vice", + "That's all there is to it!" + ] }, { "component": { @@ -48,11 +490,11 @@ "git": { "name": "nodejs", "repositoryUrl": "https://github.com/nodejs/node", - "commitHash": "acb71eab779fb56bf70e8a9e0cb2e82a089a87de" + "commitHash": "442e84a358d75152556b5d087e4dd6a51615330d" } }, "isOnlyProductionDependency": true, - "version": "16.13.2" + "version": "16.14.2" }, { "component": { @@ -60,12 +502,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "6165f6afc9af6f9ab4e32f4a7a8b0818f11e766a" + "commitHash": "b05ccd812e3bb3de5b1546a313e298961653e942" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "18.3.5" + "version": "19.0.12" }, { "component": { @@ -550,7 +992,7 @@ "commitHash": "5b871f95fd9cb8efa8ee9a80600510d5e5339137" } }, - "licenseDetail":[ + "licenseDetail": [ "MIT License", "", "Copyright (c) Microsoft Corporation.", diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index fdd714a55c2..a124a0432e6 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -21,7 +21,7 @@ }, "dependencies": { "jsonc-parser": "^2.2.1", - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "capabilities": { "virtualWorkspaces": true, diff --git a/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json new file mode 100644 index 00000000000..d224f919109 --- /dev/null +++ b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json @@ -0,0 +1,189 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "customizations": { + "type": "object", + "properties": { + "codespaces": { + "type": "object", + "description": "Customizations specific to GitHub Codespaces", + "properties": { + "repositories": { + "type": "object", + "description": "Configuration relative to the given repositories, following the format 'owner/repo'.\n A wildcard (*) is permitted for the repo name (eg: 'microsoft/*')", + "patternProperties": { + "^[a-zA-Z0-9-_.]+[.]*\/[a-zA-Z0-9-_*]+[.]*$": { + "type": "object", + "additionalProperties": true, + "oneOf": [ + { + "properties": { + "permissions": { + "type": "object", + "description": "Additional repository permissions.\n See https://aka.ms/ghcs/multi-repo-auth for more info.", + "additionalProperties": true, + "anyOf": [ + { + "properties": { + "actions": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "checks": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "contents": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "deployments": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "discussions": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "issues": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "packages": { + "type": "string", + "enum": [ + "read" + ] + } + } + }, + { + "properties": { + "pages": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "pull_requests": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "repository_projects": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "statuses": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "workflows": { + "type": "string", + "enum": [ + "write" + ] + } + } + } + ] + } + } + }, + { + "properties": { + "permissions": { + "type": "string", + "description": "Additional repository permissions.\n See https://aka.ms/ghcs/multi-repo-auth for more info.", + "enum": [ + "read-all", + "write-all" + ] + } + } + } + ] + } + } + } + } + } + } + }, + "codespaces": { + "type": "object", + "additionalProperties": true, + "description": "Codespaces-specific configuration.", + "deprecated": true, + "deprecationMessage": "Use 'customizations/codespaces' instead" + } + } +} diff --git a/extensions/configuration-editing/schemas/devContainer.vscode.schema.json b/extensions/configuration-editing/schemas/devContainer.vscode.schema.json new file mode 100644 index 00000000000..e0f2a8aa68f --- /dev/null +++ b/extensions/configuration-editing/schemas/devContainer.vscode.schema.json @@ -0,0 +1,56 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "customizations": { + "type": "object", + "properties": { + "vscode": { + "type": "object", + "properties": { + "extensions": { + "type": "array", + "description": "An array of extensions that should be installed into the container.", + "items": { + "type": "string", + "pattern": "^([a-z0-9A-Z][a-z0-9A-Z-]*)\\.([a-z0-9A-Z][a-z0-9A-Z-]*)(@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)?$", + "errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'." + } + }, + "settings": { + "$ref": "vscode://schemas/settings/machine", + "description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again." + }, + "devPort": { + "type": "integer", + "description": "The port VS Code can use to connect to its backend." + } + } + } + } + }, + "extensions": { + "type": "array", + "description": "An array of extensions that should be installed into the container.", + "items": { + "type": "string", + "pattern": "^([a-z0-9A-Z][a-z0-9A-Z-]*)\\.([a-z0-9A-Z][a-z0-9A-Z-]*)((@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)|@prerelease)?$", + "errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'." + }, + "deprecated": true, + "deprecationMessage": "Use 'customizations/vscode/extensions' instead" + }, + "settings": { + "$ref": "vscode://schemas/settings/machine", + "description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again.", + "deprecated": true, + "deprecationMessage": "Use 'customizations/vscode/settings' instead" + }, + "devPort": { + "type": "integer", + "description": "The port VS Code can use to connect to its backend.", + "deprecated": true, + "deprecationMessage": "Use 'customizations/vscode/devPort' instead" + } + } +} diff --git a/extensions/configuration-editing/src/configurationEditingMain.ts b/extensions/configuration-editing/src/configurationEditingMain.ts index f63aa685cbe..224a57370b4 100644 --- a/extensions/configuration-editing/src/configurationEditingMain.ts +++ b/extensions/configuration-editing/src/configurationEditingMain.ts @@ -40,8 +40,8 @@ function registerVariableCompletions(pattern: string): vscode.Disposable { provideCompletionItems(document, position, _token) { const location = getLocation(document.getText(), document.offsetAt(position)); if (isCompletingInsidePropertyStringValue(document, location, position)) { - let range = document.getWordRangeAtPosition(position, /\$\{[^\}]*\}/); - if (!range || range.end.isEqual(position) || range.start.isEqual(position)) { + let range = document.getWordRangeAtPosition(position, /\$\{[^"\}]*\}?/); + if (!range || range.start.isEqual(position) || range.end.isEqual(position) && document.getText(range).endsWith('}')) { range = new vscode.Range(position, position); } diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index a4c0e3945d8..ab41c8220c2 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -96,8 +96,8 @@ export class SettingsDocument { return completions; } - let range = this.document.getWordRangeAtPosition(pos, /\$\{[^\}]*\}/); - if (!range || range.end.isEqual(pos) || range.start.isEqual(pos)) { + let range = this.document.getWordRangeAtPosition(pos, /\$\{[^"\}]*\}?/); + if (!range || range.start.isEqual(pos) || range.end.isEqual(pos) && this.document.getText(range).endsWith('}')) { range = new vscode.Range(pos, pos); } diff --git a/extensions/configuration-editing/src/test/completion.test.ts b/extensions/configuration-editing/src/test/completion.test.ts index 3df7024fa12..e5aec5fc46a 100644 --- a/extensions/configuration-editing/src/test/completion.test.ts +++ b/extensions/configuration-editing/src/test/completion.test.ts @@ -73,6 +73,20 @@ suite('Completions in settings.json', () => { const expected = { label: '${activeEditorMedium}', resultText }; await testCompletion(testFile, 'jsonc', content, expected); } + { // replacing a partial variable + const content = [ + '{', + ' "window.title": "${a|"', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "window.title": "${dirty}"', + '}', + ].join('\n'); + const expected = { label: '${dirty}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } { // inserting a literal const content = [ '{', @@ -382,6 +396,32 @@ suite('Completions in launch.json', () => { const expected = { label: '${cwd}', resultText }; await testCompletion(testFile, 'jsonc', content, expected); } + { + const content = [ + '{', + ' "version": "0.2.0",', + ' "configurations": [', + ' {', + ' "name": "Do It",', + ' "program": "${workspace|"', + ' }', + ' ]', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "version": "0.2.0",', + ' "configurations": [', + ' {', + ' "name": "Do It",', + ' "program": "${cwd}"', + ' }', + ' ]', + '}', + ].join('\n'); + const expected = { label: '${cwd}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } }); }); diff --git a/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock index f7ac959fc09..e8272098f1e 100644 --- a/extensions/configuration-editing/yarn.lock +++ b/extensions/configuration-editing/yarn.lock @@ -12,7 +12,7 @@ jsonc-parser@^2.2.1: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc" integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/cpp/cgmanifest.json b/extensions/cpp/cgmanifest.json index 29876c8523b..79c46dad831 100644 --- a/extensions/cpp/cgmanifest.json +++ b/extensions/cpp/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "jeff-hykin/better-cpp-syntax", "repositoryUrl": "https://github.com/jeff-hykin/better-cpp-syntax", - "commitHash": "ddcaa65af8a578881e0d38f3c1cf5259a1128ab5" + "commitHash": "924295fc44bde1a00fab60da3a2caca4509adb25" } }, "license": "MIT", - "version": "1.15.17", + "version": "1.15.18", "description": "The original JSON grammars were derived from https://github.com/atom/language-c which was originally converted from the C TextMate bundle https://github.com/textmate/c.tmbundle." }, { diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index 9a88814ff35..2bf73923d91 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -6,7 +6,8 @@ "brackets": [ ["{", "}"], ["[", "]"], - ["(", ")"] + ["(", ")"], + ["#if","#endif"], ], "autoClosingPairs": [ { "open": "[", "close": "]" }, diff --git a/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json b/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json index c85993386c5..b8a6aa53111 100644 --- a/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json +++ b/extensions/cpp/syntaxes/cpp.embedded.macro.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/better-cpp-syntax/commit/ddcaa65af8a578881e0d38f3c1cf5259a1128ab5", + "version": "https://github.com/jeff-hykin/better-cpp-syntax/commit/924295fc44bde1a00fab60da3a2caca4509adb25", "name": "C++", "scopeName": "source.cpp.embedded.macro", "patterns": [ @@ -519,7 +519,7 @@ "name": "comment.block.cpp" }, "builtin_storage_type_initilizer": { - "begin": "(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "\\s*+((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", "end": "\\}|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?|\\?\\?>)(?:(?:\\s)+)?(;)|(;))|(?=[;>\\[\\]=]))|(?=(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\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<11>?)+>)(?:\\s)*+)?(\\()", + "begin": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\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<11>?)+>)(?:\\s)*+)?(\\()", "end": "\\)|(?=(?))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<60>?)+>)?(?![\\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)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\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)))(?=\\()", + "begin": "(?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)?(?![\\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)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\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)))(?=\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<23>?)+>)?(?![\\w<:.]))", + "match": "(?<=^|\\))(?:(?:\\s)+)?(->)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "punctuation.definition.function.return-type.cpp" @@ -4240,7 +4240,7 @@ ] }, "function_pointer": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<12>?)+>)?(?![\\w<:.]))", + "match": "(?<=protected|virtual|private|public|,|:)(?:(?:\\s)+)?(?!(?:(?:(?:protected)|(?:private)|(?:public))|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -5770,7 +5770,7 @@ "include": "#attributes_context" }, { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<55>?)+>)?(?![\\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)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\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)))(?=\\<|\\()", + "begin": "(?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)?(?![\\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)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\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)))(?=\\<|\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -7351,7 +7351,7 @@ "include": "source.cpp#vararg_ellipses" }, { - "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -9428,7 +9428,7 @@ "endCaptures": {}, "patterns": [ { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()|(?=(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "\\s*+((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -2176,7 +2176,7 @@ ] }, "control_flow_keywords": { - "match": "((?:((?:(?>(?:\\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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", "end": "\\}", "beginCaptures": { "1": { @@ -3363,7 +3363,7 @@ ] }, "destructor_root": { - "begin": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -3784,7 +3784,7 @@ "match": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?|\\?\\?>)(?:(?:\\s)+)?(;)|(;))|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -4519,7 +4519,7 @@ ] }, "function_call": { - "begin": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\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<11>?)+>)(?:\\s)*+)?(\\()", + "begin": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\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<11>?)+>)(?:\\s)*+)?(\\()", "end": "\\)", "beginCaptures": { "1": { @@ -4593,7 +4593,7 @@ ] }, "function_definition": { - "begin": "(?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<60>?)+>)?(?![\\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)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\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)))(?=\\()", + "begin": "(?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)?(?![\\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)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\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)))(?=\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -5156,7 +5156,7 @@ ] }, { - "match": "(?<=^|\\))(?:(?:\\s)+)?(->)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<23>?)+>)?(?![\\w<:.]))", + "match": "(?<=^|\\))(?:(?:\\s)+)?(->)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "punctuation.definition.function.return-type.cpp" @@ -5404,7 +5404,7 @@ ] }, "function_pointer": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "beginCaptures": { "1": { @@ -5755,7 +5755,7 @@ ] }, "function_pointer_parameter": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "beginCaptures": { "1": { @@ -6174,19 +6174,16 @@ ] }, "goto_statement": { - "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}))*)", + "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": { + "2": { "patterns": [ { "match": "(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))", @@ -6213,7 +6210,44 @@ } ] }, + "3": { + "name": "keyword.control.goto.cpp" + }, "4": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "5": { + "patterns": [ + { + "match": "(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))", + "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" + } + ] + } + } + } + ] + }, + "6": { "name": "entity.name.label.call.cpp" } } @@ -6476,7 +6510,7 @@ "name": "storage.type.modifier.virtual.cpp" }, { - "match": "(?<=protected|virtual|private|public|,|:)(?:(?:\\s)+)?(?!(?:(?:(?:protected)|(?:private)|(?:public))|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<12>?)+>)?(?![\\w<:.]))", + "match": "(?<=protected|virtual|private|public|,|:)(?:(?:\\s)+)?(?!(?:(?:(?:protected)|(?:private)|(?:public))|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -6674,7 +6708,7 @@ ] }, "inline_builtin_storage_type": { - "match": "(?:\\s)*+(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?\\*|->)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:(?:\\s)+)?(?:(?:\\.\\*|\\.)|(?:->\\*|->))(?:(?:\\s)+)?)*)(?:(?:\\s)+)?(\\b(?!uint_least32_t[^\\w]|uint_least16_t[^\\w]|uint_least64_t[^\\w]|int_least32_t[^\\w]|int_least64_t[^\\w]|uint_fast32_t[^\\w]|uint_fast64_t[^\\w]|uint_least8_t[^\\w]|uint_fast16_t[^\\w]|int_least16_t[^\\w]|int_fast16_t[^\\w]|int_least8_t[^\\w]|uint_fast8_t[^\\w]|int_fast64_t[^\\w]|int_fast32_t[^\\w]|int_fast8_t[^\\w]|suseconds_t[^\\w]|useconds_t[^\\w]|in_addr_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|in_port_t[^\\w]|uintptr_t[^\\w]|blksize_t[^\\w]|uint32_t[^\\w]|uint64_t[^\\w]|u_quad_t[^\\w]|intmax_t[^\\w]|intmax_t[^\\w]|unsigned[^\\w]|blkcnt_t[^\\w]|uint16_t[^\\w]|intptr_t[^\\w]|swblk_t[^\\w]|wchar_t[^\\w]|u_short[^\\w]|qaddr_t[^\\w]|caddr_t[^\\w]|daddr_t[^\\w]|fixpt_t[^\\w]|nlink_t[^\\w]|segsz_t[^\\w]|clock_t[^\\w]|ssize_t[^\\w]|int16_t[^\\w]|int32_t[^\\w]|int64_t[^\\w]|uint8_t[^\\w]|int8_t[^\\w]|mode_t[^\\w]|quad_t[^\\w]|ushort[^\\w]|u_long[^\\w]|u_char[^\\w]|double[^\\w]|signed[^\\w]|time_t[^\\w]|size_t[^\\w]|key_t[^\\w]|div_t[^\\w]|ino_t[^\\w]|uid_t[^\\w]|gid_t[^\\w]|off_t[^\\w]|pid_t[^\\w]|float[^\\w]|dev_t[^\\w]|u_int[^\\w]|short[^\\w]|bool[^\\w]|id_t[^\\w]|uint[^\\w]|long[^\\w]|char[^\\w]|void[^\\w]|auto[^\\w]|id_t[^\\w]|int[^\\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(?!\\())", + "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_least16_t[^\\w]|uint_least32_t[^\\w]|uint_least64_t[^\\w]|int_least16_t[^\\w]|int_least32_t[^\\w]|int_least64_t[^\\w]|uint_least8_t[^\\w]|uint_fast16_t[^\\w]|uint_fast32_t[^\\w]|uint_fast64_t[^\\w]|int_least8_t[^\\w]|int_fast16_t[^\\w]|int_fast32_t[^\\w]|int_fast64_t[^\\w]|uint_fast8_t[^\\w]|suseconds_t[^\\w]|int_fast8_t[^\\w]|useconds_t[^\\w]|blksize_t[^\\w]|in_addr_t[^\\w]|in_port_t[^\\w]|uintptr_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|unsigned[^\\w]|u_quad_t[^\\w]|blkcnt_t[^\\w]|uint16_t[^\\w]|uint32_t[^\\w]|uint64_t[^\\w]|intptr_t[^\\w]|intmax_t[^\\w]|intmax_t[^\\w]|wchar_t[^\\w]|u_short[^\\w]|qaddr_t[^\\w]|caddr_t[^\\w]|daddr_t[^\\w]|fixpt_t[^\\w]|nlink_t[^\\w]|segsz_t[^\\w]|swblk_t[^\\w]|clock_t[^\\w]|ssize_t[^\\w]|int16_t[^\\w]|int32_t[^\\w]|int64_t[^\\w]|uint8_t[^\\w]|signed[^\\w]|double[^\\w]|u_char[^\\w]|u_long[^\\w]|ushort[^\\w]|quad_t[^\\w]|mode_t[^\\w]|size_t[^\\w]|time_t[^\\w]|int8_t[^\\w]|short[^\\w]|float[^\\w]|u_int[^\\w]|div_t[^\\w]|dev_t[^\\w]|gid_t[^\\w]|ino_t[^\\w]|key_t[^\\w]|pid_t[^\\w]|off_t[^\\w]|uid_t[^\\w]|auto[^\\w]|void[^\\w]|char[^\\w]|long[^\\w]|bool[^\\w]|uint[^\\w]|id_t[^\\w]|id_t[^\\w]|int[^\\w])(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b(?!\\())", "captures": { "1": { "patterns": [ @@ -7575,7 +7609,7 @@ ] }, "namespace_alias": { - "match": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<8>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<8>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<55>?)+>)?(?![\\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)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\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)))(?=\\<|\\()", + "begin": "(?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)?(?![\\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)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\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)))(?=\\<|\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -10441,7 +10475,7 @@ "include": "#vararg_ellipses" }, { - "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -11479,7 +11513,7 @@ "include": "#vararg_ellipses" }, { - "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -12814,7 +12848,7 @@ ] }, "qualified_type": { - "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<11>?)+>)?(?![\\w<:.])", + "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)?(?![\\w<:.])", "captures": { "0": { "patterns": [ @@ -13084,7 +13118,7 @@ } }, "scope_resolution": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13106,7 +13140,7 @@ } }, "scope_resolution_function_call": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13128,7 +13162,7 @@ } }, "scope_resolution_function_call_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13166,7 +13200,7 @@ } }, "scope_resolution_function_definition": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13188,7 +13222,7 @@ } }, "scope_resolution_function_definition_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13226,7 +13260,7 @@ } }, "scope_resolution_function_definition_operator_overload": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13248,7 +13282,7 @@ } }, "scope_resolution_function_definition_operator_overload_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13286,7 +13320,7 @@ } }, "scope_resolution_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13324,7 +13358,7 @@ } }, "scope_resolution_namespace_alias": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13346,7 +13380,7 @@ } }, "scope_resolution_namespace_alias_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13384,7 +13418,7 @@ } }, "scope_resolution_namespace_block": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13406,7 +13440,7 @@ } }, "scope_resolution_namespace_block_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13444,7 +13478,7 @@ } }, "scope_resolution_namespace_using": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13466,7 +13500,7 @@ } }, "scope_resolution_namespace_using_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13504,7 +13538,7 @@ } }, "scope_resolution_parameter": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13526,7 +13560,7 @@ } }, "scope_resolution_parameter_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13564,7 +13598,7 @@ } }, "scope_resolution_template_call": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13586,7 +13620,7 @@ } }, "scope_resolution_template_call_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13624,7 +13658,7 @@ } }, "scope_resolution_template_definition": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13646,7 +13680,7 @@ } }, "scope_resolution_template_definition_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13688,7 +13722,7 @@ "name": "punctuation.terminator.statement.cpp" }, "simple_type": { - "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<12>?)+>)?(?![\\w<:.]))(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?", + "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -16492,7 +16526,7 @@ } }, "type_alias": { - "match": "(using)(?:(?:\\s)+)?(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<29>?)+>)?(?![\\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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<29>?)+>)?(?![\\w<:.]))|(.*(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)?(?:(?:\\s)+)?(?:(;)|\\n)", + "match": "(using)(?:(?:\\s)+)?(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)?(?![\\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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)?(?![\\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" @@ -17582,7 +17616,7 @@ "endCaptures": {}, "patterns": [ { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "beginCaptures": { "1": { @@ -18867,7 +18901,7 @@ ] }, "typename": { - "match": "(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?: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<17>?)+>)?(?![\\w<:.]))", + "match": "(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "storage.modifier.cpp" @@ -19756,7 +19790,7 @@ } }, "using_namespace": { - "begin": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((? { } test('CSS url() Path completion', async function () { - const testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + const testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(true); + const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString(true) }]; await assertCompletions('html { background-image: url("./|")', { items: [ @@ -119,8 +119,8 @@ suite('Completions', () => { }); test('CSS url() Path Completion - Unquoted url', async function () { - const testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + const testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(true); + const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString(true) }]; await assertCompletions('html { background-image: url(./|)', { items: [ @@ -148,8 +148,8 @@ suite('Completions', () => { }); test('CSS @import Path completion', async function () { - const testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + const testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(true); + const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString(true) }]; await 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', async function () { - const testCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + const testCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(true); + const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString(true) }]; /** * We are in a CSS file, so no special treatment for SCSS partial files @@ -184,7 +184,7 @@ suite('Completions', () => { ] }, testCSSUri, folders); - const testSCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/scss/main.scss')).toString(); + const testSCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/scss/main.scss')).toString(true); await assertCompletions(`@import './|'`, { items: [ { label: '_foo.scss', resultText: `@import './foo'` } @@ -193,8 +193,8 @@ suite('Completions', () => { }); test('Completion should ignore files/folders starting with dot', async function () { - const testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + const testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(true); + const folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString(true) }]; await assertCompletions('html { background-image: url("../|")', { count: 4 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 c19f67e5e4b..96bca1e4864 100644 --- a/extensions/css-language-features/server/src/test/links.test.ts +++ b/extensions/css-language-features/server/src/test/links.test.ts @@ -55,7 +55,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(true); } test('url links', async function () { diff --git a/extensions/css-language-features/server/src/utils/documentContext.ts b/extensions/css-language-features/server/src/utils/documentContext.ts index 0570ac92375..3defe4a445d 100644 --- a/extensions/css-language-features/server/src/utils/documentContext.ts +++ b/extensions/css-language-features/server/src/utils/documentContext.ts @@ -27,11 +27,11 @@ export function getDocumentContext(documentUri: string, workspaceFolders: Worksp if (ref[0] === '/') { // resolve absolute path against the current workspace folder const folderUri = getRootFolder(); if (folderUri) { - return folderUri + ref.substr(1); + return folderUri + ref.substring(1); } } - base = base.substr(0, base.lastIndexOf('/') + 1); - return Utils.resolvePath(URI.parse(base), ref).toString(); + base = base.substring(0, base.lastIndexOf('/') + 1); + return Utils.resolvePath(URI.parse(base), ref).toString(true); }, }; } diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index 9a9938963fd..4bf86843f5e 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -12,55 +12,50 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-css-languageservice@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.0.1.tgz#ccf94944e094dcc5833d1b4ac276994b698e9283" - integrity sha512-81n/eeYuJwQdvpoy6IK1258PtPbO720fl13FcJ5YQECPyHMFkmld1qKHwPJkyLbLPfboqJPM53ys4xW8v+iBVw== +vscode-css-languageservice@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.1.0.tgz#fa5408307de1bee817b65efaff284da8a2eca987" + integrity sha512-GFXmy6EVceVc/OPKENnoW31EiIksekz9yruczIAkA0eX5BSkNh/ojgeCzwW1ERRFpDymVZj0aLYKSrYZmvU6VA== dependencies: - vscode-languageserver-textdocument "^1.0.4" - vscode-languageserver-types "^3.17.1" - vscode-nls "^5.0.1" + vscode-languageserver-textdocument "^1.0.7" + vscode-languageserver-types "^3.17.2" + vscode-nls "^5.2.0" vscode-uri "^3.0.3" -vscode-jsonrpc@8.0.2-next.1: - version "8.0.2-next.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz#6bdc39fd194782032e34047eeefce562941259c6" - integrity sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA== +vscode-jsonrpc@8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0-next.1.tgz#7c38cb1cbd968c409522593004fdac845a55b155" + integrity sha512-FiPG+9TuMIga3t+kkalQytwqMtJu1djI+Pq+Ut2tvAJpcNHDJ0PYdjFv5mgEvTEJLujrYwjWHVkNe+XfHPBD/w== -vscode-languageserver-protocol@3.17.2-next.5: - version "3.17.2-next.5" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.5.tgz#9bc747411c3ce9e1d73c2714bf6555e0199eec26" - integrity sha512-UlH+QL4Q4lX94of/UPDDwwWIkd8w7dtMW4khzvEDUoykiG9tba0iG6V0bAiv8XVpnBIUYjL2FNFiL3zl+TY1Sw== +vscode-languageserver-protocol@3.17.3-next.1: + version "3.17.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3-next.1.tgz#804880c172b4c48d1a48a91c4c23250121effb19" + integrity sha512-vgjvPE0zox+1Fi4ljsSFJ+B3g8wGNbuAEEdulueVdv+R2VHtc06+dgxhWiG4LKPqXwjPDmiuxCnvd2xk3fzTTw== dependencies: - vscode-jsonrpc "8.0.2-next.1" - vscode-languageserver-types "3.17.2-next.2" + vscode-jsonrpc "8.1.0-next.1" + vscode-languageserver-types "3.17.2" -vscode-languageserver-textdocument@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" - integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== +vscode-languageserver-textdocument@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz#16df468d5c2606103c90554ae05f9f3d335b771b" + integrity sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg== -vscode-languageserver-types@3.17.2-next.2: - version "3.17.2-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" - integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== +vscode-languageserver-types@3.17.2, vscode-languageserver-types@^3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== -vscode-languageserver-types@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" - integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== - -vscode-languageserver@^8.0.2-next.4: - version "8.0.2-next.4" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2-next.4.tgz#c10cc95be06325b56b7ec1d10271c9e4adf3ef07" - integrity sha512-B3roWH4TmJiB6Zh5+r7zu0QdlLqJsPdGo0LeEi6OiLfrHYCDlcI7DNcQ7F17vWmxC3C82SrxMt/EuLBMpKQM0A== +vscode-languageserver@^8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.1.0-next.1.tgz#1c173de554889bd18ca6e20eaf4bdc84164c86b4" + integrity sha512-u14Rk4JgXI+7iS6AEXI2pNc1dWh/5JEXtaqa4TeBECKJlN+5242mbGBBPaHMOE7sSI1Kh66XhEMZJhPYjUfjHw== dependencies: - vscode-languageserver-protocol "3.17.2-next.5" + vscode-languageserver-protocol "3.17.3-next.1" -vscode-nls@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" - integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index 9b7854145e5..9e782f83e84 100644 --- a/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -12,18 +12,12 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" - concat-map "0.0.1" - -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= lru-cache@^6.0.0: version "6.0.0" @@ -32,51 +26,51 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +minimatch@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" + integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" -semver@^7.3.5: +semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -vscode-jsonrpc@8.0.2-next.1: - version "8.0.2-next.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz#6bdc39fd194782032e34047eeefce562941259c6" - integrity sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA== +vscode-jsonrpc@8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0-next.1.tgz#7c38cb1cbd968c409522593004fdac845a55b155" + integrity sha512-FiPG+9TuMIga3t+kkalQytwqMtJu1djI+Pq+Ut2tvAJpcNHDJ0PYdjFv5mgEvTEJLujrYwjWHVkNe+XfHPBD/w== -vscode-languageclient@^8.0.2-next.4: - version "8.0.2-next.4" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.2-next.4.tgz#87dd364ffbd4356aff3af14e7b557d9fe34d2b67" - integrity sha512-j9BEiCYMN9IoKwYdk9iickV6WNPVGPoVO11SMdoxFnWPIT3y5UAe3qf/WsfA9OdklAIaxxYasfgyKCpBjSPNuw== +vscode-languageclient@^8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.1.0-next.1.tgz#44b63bc2d215c13f1dea1dc54267a354ea5451cb" + integrity sha512-lJraJ8IrqXr83ZciAs4dN32f9kEPuOb/FqAeUTgnW5cAxo0Qux0/EMgKyU33Qf9LdEI0I9iwRVxQWtawbyUUfg== dependencies: - minimatch "^3.0.4" - semver "^7.3.5" - vscode-languageserver-protocol "3.17.2-next.5" + minimatch "^5.1.0" + semver "^7.3.7" + vscode-languageserver-protocol "3.17.3-next.1" -vscode-languageserver-protocol@3.17.2-next.5: - version "3.17.2-next.5" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.5.tgz#9bc747411c3ce9e1d73c2714bf6555e0199eec26" - integrity sha512-UlH+QL4Q4lX94of/UPDDwwWIkd8w7dtMW4khzvEDUoykiG9tba0iG6V0bAiv8XVpnBIUYjL2FNFiL3zl+TY1Sw== +vscode-languageserver-protocol@3.17.3-next.1: + version "3.17.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3-next.1.tgz#804880c172b4c48d1a48a91c4c23250121effb19" + integrity sha512-vgjvPE0zox+1Fi4ljsSFJ+B3g8wGNbuAEEdulueVdv+R2VHtc06+dgxhWiG4LKPqXwjPDmiuxCnvd2xk3fzTTw== dependencies: - vscode-jsonrpc "8.0.2-next.1" - vscode-languageserver-types "3.17.2-next.2" + vscode-jsonrpc "8.1.0-next.1" + vscode-languageserver-types "3.17.2" -vscode-languageserver-types@3.17.2-next.2: - version "3.17.2-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" - integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== +vscode-languageserver-types@3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/dart/cgmanifest.json b/extensions/dart/cgmanifest.json index 84f084ffdbd..d98ab2e7ef6 100644 --- a/extensions/dart/cgmanifest.json +++ b/extensions/dart/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "dart-lang/dart-syntax-highlight", "repositoryUrl": "https://github.com/dart-lang/dart-syntax-highlight", - "commitHash": "9d4857e114b7000d94232d83187ad142961c678a" + "commitHash": "bd5cbdfe533c455a7ff7875923c4a94a5b497382" } }, "licenseDetail": [ diff --git a/extensions/dart/syntaxes/dart.tmLanguage.json b/extensions/dart/syntaxes/dart.tmLanguage.json index 00f374a6ba2..2970d1067cb 100644 --- a/extensions/dart/syntaxes/dart.tmLanguage.json +++ b/extensions/dart/syntaxes/dart.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/dart-lang/dart-syntax-highlight/commit/9d4857e114b7000d94232d83187ad142961c678a", + "version": "https://github.com/dart-lang/dart-syntax-highlight/commit/bd5cbdfe533c455a7ff7875923c4a94a5b497382", "name": "Dart", "scopeName": "source.dart", "patterns": [ @@ -230,7 +230,15 @@ "class-identifier": { "patterns": [ { - "match": "(??]|,\\s*|\\s+extends\\s+)+>)?|bool\\b|num\\b|int\\b|double\\b|dynamic\\b|(void)\\b)", + "name": "storage.type.primitive.dart", + "match": "\\bvoid\\b" + }, + { + "name": "support.class.dart", + "match": "\\b(bool|num|int|double|dynamic)\\b" + }, + { + "match": "\\b([_$]*[A-Z][a-zA-Z0-9_$]*)(<(?:[a-zA-Z0-9_$<>?]|,\\s*|\\s+extends\\s+)+>)?", "captures": { "1": { "name": "support.class.dart" @@ -241,9 +249,6 @@ "include": "#type-args" } ] - }, - "3": { - "name": "storage.type.primitive.dart" } } } diff --git a/extensions/debug-auto-launch/package.json b/extensions/debug-auto-launch/package.json index 82c9054c456..80ea639b5f3 100644 --- a/extensions/debug-auto-launch/package.json +++ b/extensions/debug-auto-launch/package.json @@ -33,7 +33,7 @@ ] }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/debug-auto-launch/yarn.lock b/extensions/debug-auto-launch/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/debug-auto-launch/yarn.lock +++ b/extensions/debug-auto-launch/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -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@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/debug-server-ready/package.json b/extensions/debug-server-ready/package.json index 29cee88c0c5..3b570124452 100644 --- a/extensions/debug-server-ready/package.json +++ b/extensions/debug-server-ready/package.json @@ -150,7 +150,7 @@ ] }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/debug-server-ready/yarn.lock b/extensions/debug-server-ready/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/debug-server-ready/yarn.lock +++ b/extensions/debug-server-ready/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -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@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index d9deee50fb3..9cbe3bf74a6 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -65,6 +65,7 @@ "emmet.showAbbreviationSuggestions": { "type": "boolean", "default": true, + "scope": "language-overridable", "markdownDescription": "%emmetShowAbbreviationSuggestions%" }, "emmet.includeLanguages": { @@ -125,6 +126,7 @@ "emmet.triggerExpansionOnTab": { "type": "boolean", "default": false, + "scope": "language-overridable", "markdownDescription": "%emmetTriggerExpansionOnTab%" }, "emmet.useInlineCompletions": { diff --git a/extensions/emmet/src/emmetCommon.ts b/extensions/emmet/src/emmetCommon.ts index fc81dd9d7ed..daed62d7c65 100644 --- a/extensions/emmet/src/emmetCommon.ts +++ b/extensions/emmet/src/emmetCommon.ts @@ -204,7 +204,7 @@ function refreshCompletionProviders(_: vscode.ExtensionContext) { completionProviderDisposables.push(inlineCompletionsProvider); } - const explicitProvider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider); + const explicitProvider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[includedLanguages[language]]); completionProviderDisposables.push(explicitProvider); languageMappingForCompletionProviders.set(language, includedLanguages[language]); @@ -217,7 +217,7 @@ function refreshCompletionProviders(_: vscode.ExtensionContext) { completionProviderDisposables.push(inlineCompletionsProvider); } - const explicitProvider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider); + const explicitProvider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[language]); completionProviderDisposables.push(explicitProvider); languageMappingForCompletionProviders.set(language, language); diff --git a/extensions/extension-editing/package.json b/extensions/extension-editing/package.json index abceee2bc7d..add192a06c0 100644 --- a/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -29,7 +29,7 @@ "jsonc-parser": "^2.2.1", "markdown-it": "^12.3.2", "parse5": "^3.0.2", - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "contributes": { "jsonValidation": [ diff --git a/extensions/extension-editing/yarn.lock b/extensions/extension-editing/yarn.lock index ac87f5e2686..3aa5397f837 100644 --- a/extensions/extension-editing/yarn.lock +++ b/extensions/extension-editing/yarn.lock @@ -67,7 +67,7 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/fsharp/cgmanifest.json b/extensions/fsharp/cgmanifest.json index 6841f8c8808..a3f2c2601b8 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": "e177bd7f9d3402f70d2f1fb42c74057ed1ccf6fa" + "commitHash": "713cd4a34e7729e444cf85ae287dd94c19e34337" } }, "license": "MIT", diff --git a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json index 81c033d7146..9d1f8c1c82f 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/e177bd7f9d3402f70d2f1fb42c74057ed1ccf6fa", + "version": "https://github.com/ionide/ionide-fsgrammar/commit/713cd4a34e7729e444cf85ae287dd94c19e34337", "name": "fsharp", "scopeName": "source.fsharp", "patterns": [ @@ -928,7 +928,7 @@ "patterns": [ { "name": "binding.fsharp", - "begin": "\\b(let mutable|static let mutable|static let|let inline|let|member val|static member inline|static member|default|member|override|let!)(\\s+rec|mutable)?(\\s+\\[\\<.*\\>\\])?\\s*(private|internal|public)?\\s+(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9\\._`\\s]+|(?<=,)\\s)*)?", + "begin": "\\b(let mutable|static let mutable|static let|let inline|let|and|member val|static member inline|static member|default|member|override|let!)(\\s+rec|mutable)?(\\s+\\[\\<.*\\>\\])?\\s*(private|internal|public)?\\s+(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9\\._`\\s]+|(?<=,)\\s)*)?", "end": "\\s*(with\\b|=|\\n+=|(?<=\\=))", "beginCaptures": { "1": { @@ -960,7 +960,7 @@ }, { "name": "binding.fsharp", - "begin": "\\b(use|use\\!|and|and!)\\s*(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9\\._`\\s]+|(?<=,)\\s)*)?", + "begin": "\\b(use|use!|and|and!)\\s+(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9\\._`\\s]+|(?<=,)\\s)*)?", "end": "\\s*(=)", "beginCaptures": { "1": { diff --git a/extensions/git-base/package.json b/extensions/git-base/package.json index 07e95e3a1ae..1c7daa3b4b9 100644 --- a/extensions/git-base/package.json +++ b/extensions/git-base/package.json @@ -100,7 +100,7 @@ ] }, "dependencies": { - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/git-base/src/remoteSource.ts b/extensions/git-base/src/remoteSource.ts index 32b45b851f7..134af197316 100644 --- a/extensions/git-base/src/remoteSource.ts +++ b/extensions/git-base/src/remoteSource.ts @@ -70,7 +70,7 @@ class RemoteSourceProviderQuickPick { })); } } catch (err) { - this.quickpick!.items = [{ label: localize('error', "$(error) Error: {0}", err.message), alwaysShow: true }]; + this.quickpick!.items = [{ label: localize('error', "{0} Error: {1}", '$(error)', err.message), alwaysShow: true }]; console.error(err); } finally { this.quickpick!.busy = false; diff --git a/extensions/git-base/yarn.lock b/extensions/git-base/yarn.lock index 8fb6777123c..0cd0d3ce8f2 100644 --- a/extensions/git-base/yarn.lock +++ b/extensions/git-base/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.21.tgz#474d7589a30afcf5291f59bd49cca9ad171ffde4" integrity sha512-Pf8M1XD9i1ksZEcCP8vuSNwooJ/bZapNmIzpmsMaL+jMI+8mEYU3PKvs+xDNuQcJWF/x24WzY4qxLtB0zNow9A== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/git/package.json b/extensions/git/package.json index acd208f3ac1..6f31cf07f90 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -8,21 +8,25 @@ "engines": { "vscode": "^1.5.0" }, - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "enabledApiProposals": [ "diffCommand", - "contribMergeEditorToolbar", + "contribEditorContentMenu", "contribViewsWelcome", + "editSessionIdentityProvider", "scmActionButton", "scmSelectedProvider", "scmValidation", - "timeline" + "tabInputTextMerge", + "timeline", + "contribMergeEditorMenus" ], "categories": [ "Other" ], "activationEvents": [ "*", + "onEditSession:file", "onFileSystem:git", "onFileSystem:git-show" ], @@ -365,6 +369,11 @@ "title": "%command.merge%", "category": "Git" }, + { + "command": "git.mergeAbort", + "title": "%command.mergeAbort%", + "category": "Git" + }, { "command": "git.rebase", "title": "%command.rebase%", @@ -600,6 +609,23 @@ "command": "git.acceptMerge", "title": "%command.git.acceptMerge%", "category": "Git", + "enablement": "isMergeEditor && mergeEditorResultUri in git.mergeChanges" + }, + { + "command": "git.openMergeEditor", + "title": "%command.git.openMergeEditor%", + "category": "Git" + }, + { + "command": "git.runGitMerge", + "title": "%command.git.runGitMerge%", + "category": "Git", + "enablement": "isMergeEditor" + }, + { + "command": "git.runGitMergeDiff3", + "title": "%command.git.runGitMergeDiff3%", + "category": "Git", "enablement": "isMergeEditor" } ], @@ -877,6 +903,10 @@ "command": "git.merge", "when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0" }, + { + "command": "git.mergeAbort", + "when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && gitMergeInProgress" + }, { "command": "git.rebase", "when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0" @@ -1024,6 +1054,10 @@ { "command": "git.api.getRemoteSources", "when": "false" + }, + { + "command": "git.openMergeEditor", + "when": "false" } ], "scm/title": [ @@ -1545,10 +1579,25 @@ "when": "isInDiffRightEditor && !isInEmbeddedDiffEditor && config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/" } ], - "merge/toolbar": [ + "editor/content": [ { "command": "git.acceptMerge", - "when": "isMergeEditor && baseResourceScheme =~ /^git$|^file$/" + "when": "isMergeResultEditor && mergeEditorBaseUri =~ /^(git|file):/ && mergeEditorResultUri in git.mergeChanges" + }, + { + "command": "git.openMergeEditor", + "group": "navigation@-10", + "when": "config.git.enabled && !git.missing && !isInDiffEditor && !isMergeEditor && resource in git.mergeChanges" + } + ], + "mergeEditor/result/title": [ + { + "command": "git.runGitMerge", + "when": "isMergeEditor" + }, + { + "command": "git.runGitMergeDiff3", + "when": "isMergeEditor" } ], "scm/change/title": [ @@ -2175,6 +2224,12 @@ "scope": "resource", "default": "none" }, + "git.rememberPostCommitCommand": { + "type": "boolean", + "description": "%config.rememberPostCommitCommand%", + "scope": "resource", + "default": false + }, "git.openAfterClone": { "type": "string", "enum": [ @@ -2521,7 +2576,7 @@ }, "git.mergeEditor": { "type": "boolean", - "default": false, + "default": true, "markdownDescription": "%config.mergeEditor%", "scope": "window" } @@ -2712,19 +2767,18 @@ }, "dependencies": { "@joaomoreno/unique-names-generator": "5.0.0", - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "@vscode/iconv-lite-umd": "0.7.0", "byline": "^5.0.0", - "file-type": "^7.2.0", + "file-type": "16.5.4", "jschardet": "3.0.0", "picomatch": "2.3.1", - "vscode-nls": "^4.0.0", + "vscode-nls": "^5.1.0", "vscode-uri": "^2.0.0", "which": "^1.3.0" }, "devDependencies": { "@types/byline": "4.2.31", - "@types/file-type": "^5.2.1", "@types/mocha": "^9.1.1", "@types/node": "16.x", "@types/picomatch": "2.3.0", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 2477a55fa76..9cb0eedbf1d 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -58,6 +58,7 @@ "command.renameBranch": "Rename Branch...", "command.cherryPick": "Cherry Pick...", "command.merge": "Merge Branch...", + "command.mergeAbort": "Abort Merge", "command.rebase": "Rebase Branch...", "command.createTag": "Create Tag", "command.deleteTag": "Delete Tag", @@ -103,6 +104,9 @@ "command.api.getRepositoryState": "Get Repository State", "command.api.getRemoteSources": "Get Remote Sources", "command.git.acceptMerge": "Accept Merge", + "command.git.openMergeEditor": "Open in Merge Editor", + "command.git.runGitMerge": "Compute Conflicts With Git", + "command.git.runGitMergeDiff3": "Compute Conflicts With Git (Diff3)", "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). This can also be an array of string values containing multiple paths to look up.", "config.autoRepositoryDetection": "Configures when repositories should be automatically detected.", @@ -162,10 +166,11 @@ "config.promptToSaveFilesBeforeCommit.always": "Check for any unsaved files.", "config.promptToSaveFilesBeforeCommit.staged": "Check only for unsaved staged files.", "config.promptToSaveFilesBeforeCommit.never": "Disable this check.", - "config.postCommitCommand": "Runs a git command after a successful commit.", + "config.postCommitCommand": "Run a git command after a successful commit.", "config.postCommitCommand.none": "Don't run any command after a commit.", - "config.postCommitCommand.push": "Run 'Git Push' after a successful commit.", - "config.postCommitCommand.sync": "Run 'Git Sync' after a successful commit.", + "config.postCommitCommand.push": "Run 'git push' after a successful commit.", + "config.postCommitCommand.sync": "Run 'git pull' and 'git push' after a successful commit.", + "config.rememberPostCommitCommand": "Remember the last git command that ran after a commit.", "config.openAfterClone": "Controls whether to open a repository automatically after cloning.", "config.openAfterClone.always": "Always open in current window.", "config.openAfterClone.alwaysNewWindow": "Always open in a new window.", @@ -221,10 +226,10 @@ "config.timeline.date.committed": "Use the committed date", "config.timeline.date.authored": "Use the authored date", "config.useCommitInputAsStashMessage": "Controls whether to use the message from the commit input box as the default stash message.", - "config.showActionButton": "Controls whether an action button can be shown in the Source Control view.", - "config.showActionButton.commit": "Show an action button to commit changes.", - "config.showActionButton.publish": "Show an action button to publish a local branch.", - "config.showActionButton.sync": "Show an action button to sync changes.", + "config.showActionButton": "Controls whether an action button is shown in the Source Control view.", + "config.showActionButton.commit": "Show an action button to commit changes when the local branch has modified files ready to be committed.", + "config.showActionButton.publish": "Show an action button to publish the local branch when it does not have a tracking remote branch.", + "config.showActionButton.sync": "Show an action button to synchronize changes when the local branch is either ahead or behind the remote branch.", "config.statusLimit": "Controls how to limit the number of changes that can be parsed from Git status command. Can be set to 0 for no limit.", "config.experimental.installGuide": "Experimental improvements for the git setup flow.", "config.repositoryScanIgnoredFolders": "List of folders that are ignored while scanning for Git repositories when `#git.autoRepositoryDetection#` is set to `true` or `subFolders`.", diff --git a/extensions/git/src/actionButton.ts b/extensions/git/src/actionButton.ts index 2eabbeaa9e6..cd818323e36 100644 --- a/extensions/git/src/actionButton.ts +++ b/extensions/git/src/actionButton.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace } from 'vscode'; import * as nls from 'vscode-nls'; +import { Command, Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace } from 'vscode'; +import { Branch, CommitCommand, Status } from './api/git'; +import { CommitCommandsCenter } from './postCommitCommands'; import { Repository, Operation } from './repository'; import { dispose } from './util'; -import { Branch } from './api/git'; const localize = nls.loadMessageBundle(); @@ -15,8 +16,9 @@ interface ActionButtonState { readonly HEAD: Branch | undefined; readonly isCommitInProgress: boolean; readonly isMergeInProgress: boolean; + readonly isRebaseInProgress: boolean; readonly isSyncInProgress: boolean; - readonly repositoryHasChanges: boolean; + readonly repositoryHasChangesToCommit: boolean; } export class ActionButtonCommand { @@ -34,34 +36,47 @@ export class ActionButtonCommand { private disposables: Disposable[] = []; - constructor(readonly repository: Repository) { + constructor( + readonly repository: Repository, + readonly postCommitCommandCenter: CommitCommandsCenter) { this._state = { HEAD: undefined, isCommitInProgress: false, isMergeInProgress: false, + isRebaseInProgress: false, isSyncInProgress: false, - repositoryHasChanges: false + repositoryHasChangesToCommit: false }; repository.onDidRunGitStatus(this.onDidRunGitStatus, this, this.disposables); repository.onDidChangeOperations(this.onDidChangeOperations, this, this.disposables); + this.disposables.push(postCommitCommandCenter.onDidChange(() => this._onDidChange.fire())); + const root = Uri.file(repository.root); this.disposables.push(workspace.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('git.postCommitCommand', root) || - e.affectsConfiguration('git.showActionButton', root) - ) { + if (e.affectsConfiguration('git.enableSmartCommit', root) || + e.affectsConfiguration('git.smartCommitChanges', root) || + e.affectsConfiguration('git.suggestSmartCommit', root)) { + this.onDidChangeSmartCommitSettings(); + } + + if (e.affectsConfiguration('git.branchProtection', root) || + e.affectsConfiguration('git.branchProtectionPrompt', root) || + e.affectsConfiguration('git.postCommitCommand', root) || + e.affectsConfiguration('git.rememberPostCommitCommand', root) || + e.affectsConfiguration('git.showActionButton', root)) { this._onDidChange.fire(); } })); } get button(): SourceControlActionButton | undefined { - if (!this.state.HEAD || !this.state.HEAD.name) { return undefined; } + if (!this.state.HEAD) { return undefined; } let actionButton: SourceControlActionButton | undefined; - if (this.state.repositoryHasChanges) { + if (this.state.repositoryHasChangesToCommit) { // Commit Changes (enabled) actionButton = this.getCommitActionButton(); } @@ -77,77 +92,63 @@ export class ActionButtonCommand { // The button is disabled if (!showActionButton.commit) { return undefined; } - let title: string, tooltip: string; - const postCommitCommand = config.get('postCommitCommand'); - - switch (postCommitCommand) { - case 'push': { - title = localize('scm button commit and push title', "$(arrow-up) Commit & Push"); - tooltip = this.state.isCommitInProgress ? - localize('scm button committing pushing tooltip', "Committing & Pushing Changes...") : - localize('scm button commit push tooltip', "Commit & Push Changes"); - break; - } - case 'sync': { - title = localize('scm button commit and sync title', "$(sync) Commit & Sync"); - tooltip = this.state.isCommitInProgress ? - localize('scm button committing synching tooltip', "Committing & Synching Changes...") : - localize('scm button commit sync tooltip', "Commit & Sync Changes"); - break; - } - default: { - title = localize('scm button commit title', "$(check) Commit"); - tooltip = this.state.isCommitInProgress ? - localize('scm button committing tooltip', "Committing Changes...") : - localize('scm button commit tooltip', "Commit Changes"); - break; - } - } + const primaryCommand = this.getCommitActionButtonPrimaryCommand(); return { - command: { - command: 'git.commit', - title: title, - tooltip: tooltip, - arguments: [this.repository.sourceControl], - }, - secondaryCommands: [ - [ - { - command: 'git.commit', - title: localize('scm secondary button commit', "Commit"), - arguments: [this.repository.sourceControl, ''], - }, - { - command: 'git.commit', - title: localize('scm secondary button commit and push', "Commit & Push"), - arguments: [this.repository.sourceControl, 'push'], - }, - { - command: 'git.commit', - title: localize('scm secondary button commit and sync', "Commit & Sync"), - arguments: [this.repository.sourceControl, 'sync'], - }, - ] - ], - enabled: this.state.repositoryHasChanges && !this.state.isCommitInProgress && !this.state.isMergeInProgress + command: primaryCommand, + secondaryCommands: this.getCommitActionButtonSecondaryCommands(), + description: primaryCommand.description ?? primaryCommand.title, + enabled: (this.state.repositoryHasChangesToCommit || this.state.isRebaseInProgress) && !this.state.isCommitInProgress && !this.state.isMergeInProgress }; } + private getCommitActionButtonPrimaryCommand(): CommitCommand { + // Rebase Continue + if (this.state.isRebaseInProgress) { + return { + command: 'git.commit', + title: localize('scm button continue title', "{0} Continue", '$(check)'), + tooltip: this.state.isCommitInProgress ? localize('scm button continuing tooltip', "Continuing Rebase...") : localize('scm button continue tooltip', "Continue Rebase"), + arguments: [this.repository.sourceControl, ''] + }; + } + + // Commit + return this.postCommitCommandCenter.getPrimaryCommand(); + } + + private getCommitActionButtonSecondaryCommands(): Command[][] { + // Rebase Continue + if (this.state.isRebaseInProgress) { + return []; + } + + // Commit + const commandGroups: Command[][] = []; + for (const commands of this.postCommitCommandCenter.getSecondaryCommands()) { + commandGroups.push(commands.map(c => { + // Use the description as title if present + return { command: 'git.commit', title: c.description ?? c.title, tooltip: c.tooltip, arguments: c.arguments }; + })); + } + + return commandGroups; + } + private getPublishBranchActionButton(): SourceControlActionButton | undefined { const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); const showActionButton = config.get<{ publish: boolean }>('showActionButton', { publish: true }); - // Branch does have an upstream, commit/merge is in progress, or the button is disabled - if (this.state.HEAD?.upstream || this.state.isCommitInProgress || this.state.isMergeInProgress || !showActionButton.publish) { return undefined; } + // Branch does have an upstream, commit/merge/rebase is in progress, or the button is disabled + if (this.state.HEAD?.upstream || this.state.isCommitInProgress || this.state.isMergeInProgress || this.state.isRebaseInProgress || !showActionButton.publish) { return undefined; } return { command: { command: 'git.publish', - title: localize('scm publish branch action button title', "{0} Publish Branch", '$(cloud-upload)'), + title: localize({ key: 'scm publish branch action button title', comment: ['{Locked="Branch"}', 'Do not translate "Branch" as it is a git term'] }, "{0} Publish Branch", '$(cloud-upload)'), tooltip: this.state.isSyncInProgress ? - localize('scm button publish branch running', "Publishing Branch...") : - localize('scm button publish branch', "Publish Branch"), + localize({ key: 'scm button publish branch running', comment: ['{Locked="Branch"}', 'Do not translate "Branch" as it is a git term'] }, "Publishing Branch...") : + localize({ key: 'scm button publish branch', comment: ['{Locked="Branch"}', 'Do not translate "Branch" as it is a git term'] }, "Publish Branch"), arguments: [this.repository.sourceControl], }, enabled: !this.state.isSyncInProgress @@ -157,19 +158,18 @@ export class ActionButtonCommand { private getSyncChangesActionButton(): SourceControlActionButton | undefined { const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); const showActionButton = config.get<{ sync: boolean }>('showActionButton', { sync: true }); + const branchIsAheadOrBehind = (this.state.HEAD?.behind ?? 0) > 0 || (this.state.HEAD?.ahead ?? 0) > 0; - // Branch does not have an upstream, commit/merge is in progress, or the button is disabled - if (!this.state.HEAD?.upstream || this.state.isCommitInProgress || this.state.isMergeInProgress || !showActionButton.sync) { return undefined; } + // Branch does not have an upstream, branch is not ahead/behind the remote branch, commit/merge/rebase is in progress, or the button is disabled + if (!this.state.HEAD?.upstream || !branchIsAheadOrBehind || this.state.isCommitInProgress || this.state.isMergeInProgress || this.state.isRebaseInProgress || !showActionButton.sync) { return undefined; } const ahead = this.state.HEAD.ahead ? ` ${this.state.HEAD.ahead}$(arrow-up)` : ''; const behind = this.state.HEAD.behind ? ` ${this.state.HEAD.behind}$(arrow-down)` : ''; const icon = this.state.isSyncInProgress ? '$(sync~spin)' : '$(sync)'; - const rebaseWhenSync = config.get('rebaseWhenSync'); - return { command: { - command: rebaseWhenSync ? 'git.syncRebase' : 'git.sync', + command: 'git.sync', title: `${icon}${behind}${ahead}`, tooltip: this.state.isSyncInProgress ? localize('syncing changes', "Synchronizing Changes...") @@ -183,7 +183,8 @@ export class ActionButtonCommand { private onDidChangeOperations(): void { const isCommitInProgress = - this.repository.operations.isRunning(Operation.Commit); + this.repository.operations.isRunning(Operation.Commit) || + this.repository.operations.isRunning(Operation.RebaseContinue); const isSyncInProgress = this.repository.operations.isRunning(Operation.Sync) || @@ -193,19 +194,48 @@ export class ActionButtonCommand { this.state = { ...this.state, isCommitInProgress, isSyncInProgress }; } + private onDidChangeSmartCommitSettings(): void { + this.state = { + ...this.state, + repositoryHasChangesToCommit: this.repositoryHasChangesToCommit() + }; + } + private onDidRunGitStatus(): void { this.state = { ...this.state, HEAD: this.repository.HEAD, - isMergeInProgress: - this.repository.mergeGroup.resourceStates.length !== 0, - repositoryHasChanges: - this.repository.indexGroup.resourceStates.length !== 0 || - this.repository.untrackedGroup.resourceStates.length !== 0 || - this.repository.workingTreeGroup.resourceStates.length !== 0 + isMergeInProgress: this.repository.mergeInProgress, + isRebaseInProgress: !!this.repository.rebaseCommit, + repositoryHasChangesToCommit: this.repositoryHasChangesToCommit() }; } + private repositoryHasChangesToCommit(): boolean { + const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); + const enableSmartCommit = config.get('enableSmartCommit') === true; + const suggestSmartCommit = config.get('suggestSmartCommit') === true; + const smartCommitChanges = config.get<'all' | 'tracked'>('smartCommitChanges', 'all'); + + const resources = [...this.repository.indexGroup.resourceStates]; + + if ( + // Smart commit enabled (all) + (enableSmartCommit && smartCommitChanges === 'all') || + // Smart commit disabled, smart suggestion enabled + (!enableSmartCommit && suggestSmartCommit) + ) { + resources.push(...this.repository.workingTreeGroup.resourceStates); + } + + // Smart commit enabled (tracked only) + if (enableSmartCommit && smartCommitChanges === 'tracked') { + resources.push(...this.repository.workingTreeGroup.resourceStates.filter(r => r.type !== Status.UNTRACKED)); + } + + return resources.length !== 0; + } + dispose(): void { this.disposables = dispose(this.disposables); } diff --git a/extensions/git/src/api/api1.ts b/extensions/git/src/api/api1.ts index 32417c2a6d1..4581eaa1abc 100644 --- a/extensions/git/src/api/api1.ts +++ b/extensions/git/src/api/api1.ts @@ -5,7 +5,7 @@ import { Model } from '../model'; import { Repository as BaseRepository, Resource } from '../repository'; -import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher } from './git'; +import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider } from './git'; import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands } from 'vscode'; import { combinedDisposable, mapEvent } from '../util'; import { toGitUri } from '../uri'; @@ -57,157 +57,157 @@ export class ApiRepositoryUIState implements RepositoryUIState { export class ApiRepository implements Repository { - readonly rootUri: Uri = Uri.file(this._repository.root); - readonly inputBox: InputBox = new ApiInputBox(this._repository.inputBox); - readonly state: RepositoryState = new ApiRepositoryState(this._repository); - readonly ui: RepositoryUIState = new ApiRepositoryUIState(this._repository.sourceControl); + readonly rootUri: Uri = Uri.file(this.repository.root); + readonly inputBox: InputBox = new ApiInputBox(this.repository.inputBox); + readonly state: RepositoryState = new ApiRepositoryState(this.repository); + readonly ui: RepositoryUIState = new ApiRepositoryUIState(this.repository.sourceControl); - constructor(private _repository: BaseRepository) { } + constructor(readonly repository: BaseRepository) { } apply(patch: string, reverse?: boolean): Promise { - return this._repository.apply(patch, reverse); + return this.repository.apply(patch, reverse); } getConfigs(): Promise<{ key: string; value: string }[]> { - return this._repository.getConfigs(); + return this.repository.getConfigs(); } getConfig(key: string): Promise { - return this._repository.getConfig(key); + return this.repository.getConfig(key); } setConfig(key: string, value: string): Promise { - return this._repository.setConfig(key, value); + return this.repository.setConfig(key, value); } getGlobalConfig(key: string): Promise { - return this._repository.getGlobalConfig(key); + return this.repository.getGlobalConfig(key); } getObjectDetails(treeish: string, path: string): Promise<{ mode: string; object: string; size: number }> { - return this._repository.getObjectDetails(treeish, path); + return this.repository.getObjectDetails(treeish, path); } detectObjectType(object: string): Promise<{ mimetype: string; encoding?: string }> { - return this._repository.detectObjectType(object); + return this.repository.detectObjectType(object); } buffer(ref: string, filePath: string): Promise { - return this._repository.buffer(ref, filePath); + return this.repository.buffer(ref, filePath); } show(ref: string, path: string): Promise { - return this._repository.show(ref, path); + return this.repository.show(ref, path); } getCommit(ref: string): Promise { - return this._repository.getCommit(ref); + return this.repository.getCommit(ref); } add(paths: string[]) { - return this._repository.add(paths.map(p => Uri.file(p))); + return this.repository.add(paths.map(p => Uri.file(p))); } revert(paths: string[]) { - return this._repository.revert(paths.map(p => Uri.file(p))); + return this.repository.revert(paths.map(p => Uri.file(p))); } clean(paths: string[]) { - return this._repository.clean(paths.map(p => Uri.file(p))); + return this.repository.clean(paths.map(p => Uri.file(p))); } diff(cached?: boolean) { - return this._repository.diff(cached); + return this.repository.diff(cached); } diffWithHEAD(): Promise; diffWithHEAD(path: string): Promise; diffWithHEAD(path?: string): Promise { - return this._repository.diffWithHEAD(path); + return this.repository.diffWithHEAD(path); } diffWith(ref: string): Promise; diffWith(ref: string, path: string): Promise; diffWith(ref: string, path?: string): Promise { - return this._repository.diffWith(ref, path); + return this.repository.diffWith(ref, path); } diffIndexWithHEAD(): Promise; diffIndexWithHEAD(path: string): Promise; diffIndexWithHEAD(path?: string): Promise { - return this._repository.diffIndexWithHEAD(path); + return this.repository.diffIndexWithHEAD(path); } diffIndexWith(ref: string): Promise; diffIndexWith(ref: string, path: string): Promise; diffIndexWith(ref: string, path?: string): Promise { - return this._repository.diffIndexWith(ref, path); + return this.repository.diffIndexWith(ref, path); } diffBlobs(object1: string, object2: string): Promise { - return this._repository.diffBlobs(object1, object2); + return this.repository.diffBlobs(object1, object2); } diffBetween(ref1: string, ref2: string): Promise; diffBetween(ref1: string, ref2: string, path: string): Promise; diffBetween(ref1: string, ref2: string, path?: string): Promise { - return this._repository.diffBetween(ref1, ref2, path); + return this.repository.diffBetween(ref1, ref2, path); } hashObject(data: string): Promise { - return this._repository.hashObject(data); + return this.repository.hashObject(data); } createBranch(name: string, checkout: boolean, ref?: string | undefined): Promise { - return this._repository.branch(name, checkout, ref); + return this.repository.branch(name, checkout, ref); } deleteBranch(name: string, force?: boolean): Promise { - return this._repository.deleteBranch(name, force); + return this.repository.deleteBranch(name, force); } getBranch(name: string): Promise { - return this._repository.getBranch(name); + return this.repository.getBranch(name); } getBranches(query: BranchQuery): Promise { - return this._repository.getBranches(query); + return this.repository.getBranches(query); } setBranchUpstream(name: string, upstream: string): Promise { - return this._repository.setBranchUpstream(name, upstream); + return this.repository.setBranchUpstream(name, upstream); } getMergeBase(ref1: string, ref2: string): Promise { - return this._repository.getMergeBase(ref1, ref2); + return this.repository.getMergeBase(ref1, ref2); } tag(name: string, upstream: string): Promise { - return this._repository.tag(name, upstream); + return this.repository.tag(name, upstream); } deleteTag(name: string): Promise { - return this._repository.deleteTag(name); + return this.repository.deleteTag(name); } status(): Promise { - return this._repository.status(); + return this.repository.status(); } checkout(treeish: string): Promise { - return this._repository.checkout(treeish); + return this.repository.checkout(treeish); } addRemote(name: string, url: string): Promise { - return this._repository.addRemote(name, url); + return this.repository.addRemote(name, url); } removeRemote(name: string): Promise { - return this._repository.removeRemote(name); + return this.repository.removeRemote(name); } renameRemote(name: string, newName: string): Promise { - return this._repository.renameRemote(name, newName); + return this.repository.renameRemote(name, newName); } fetch(arg0?: FetchOptions | string | undefined, @@ -216,30 +216,30 @@ export class ApiRepository implements Repository { prune?: boolean | undefined ): Promise { if (arg0 !== undefined && typeof arg0 !== 'string') { - return this._repository.fetch(arg0); + return this.repository.fetch(arg0); } - return this._repository.fetch({ remote: arg0, ref, depth, prune }); + return this.repository.fetch({ remote: arg0, ref, depth, prune }); } pull(unshallow?: boolean): Promise { - return this._repository.pull(undefined, unshallow); + return this.repository.pull(undefined, unshallow); } push(remoteName?: string, branchName?: string, setUpstream: boolean = false, force?: ForcePushMode): Promise { - return this._repository.pushTo(remoteName, branchName, setUpstream, force); + return this.repository.pushTo(remoteName, branchName, setUpstream, force); } blame(path: string): Promise { - return this._repository.blame(path); + return this.repository.blame(path); } log(options?: LogOptions): Promise { - return this._repository.log(options); + return this.repository.log(options); } commit(message: string, opts?: CommitOptions): Promise { - return this._repository.commit(message, opts); + return this.repository.commit(message, opts); } } @@ -318,6 +318,10 @@ export class ApiImpl implements API { return this._model.registerCredentialsProvider(provider); } + registerPostCommitCommandsProvider(provider: PostCommitCommandsProvider): Disposable { + return this._model.registerPostCommitCommandsProvider(provider); + } + registerPushErrorHandler(handler: PushErrorHandler): Disposable { return this._model.registerPushErrorHandler(handler); } diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts index 6dfba24823e..c67f5ab7118 100644 --- a/extensions/git/src/api/git.d.ts +++ b/extensions/git/src/api/git.d.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Uri, Event, Disposable, ProviderResult } from 'vscode'; +import { Uri, Event, Disposable, ProviderResult, Command } from 'vscode'; export { ProviderResult } from 'vscode'; export interface Git { @@ -129,8 +129,6 @@ export interface LogOptions { readonly path?: string; } -export type PostCommitCommand = 'push' | 'sync' | string; - export interface CommitOptions { all?: boolean | 'tracked'; amend?: boolean; @@ -141,7 +139,7 @@ export interface CommitOptions { requireUserConfig?: boolean; useEditor?: boolean; verbose?: boolean; - postCommitCommand?: PostCommitCommand; + postCommitCommand?: string; } export interface FetchOptions { @@ -256,6 +254,12 @@ export interface CredentialsProvider { getCredentials(host: Uri): ProviderResult; } +export type CommitCommand = Command & { description?: string }; + +export interface PostCommitCommandsProvider { + getCommands(repository: Repository): CommitCommand[]; +} + export interface PushErrorHandler { handlePushError(repository: Repository, remote: Remote, refspec: string, error: Error & { gitErrorCode: GitErrorCodes }): Promise; } @@ -284,6 +288,7 @@ export interface API { registerRemoteSourcePublisher(publisher: RemoteSourcePublisher): Disposable; registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable; registerCredentialsProvider(provider: CredentialsProvider): Disposable; + registerPostCommitCommandsProvider(provider: PostCommitCommandsProvider): Disposable; registerPushErrorHandler(handler: PushErrorHandler): Disposable; } diff --git a/extensions/git/src/askpass-main.ts b/extensions/git/src/askpass-main.ts index f17dc63463f..405122a4a0b 100644 --- a/extensions/git/src/askpass-main.ts +++ b/extensions/git/src/askpass-main.ts @@ -16,24 +16,49 @@ function fatal(err: any): void { } function main(argv: string[]): void { - if (argv.length !== 5) { - return fatal('Wrong number of arguments'); - } - if (!process.env['VSCODE_GIT_ASKPASS_PIPE']) { return fatal('Missing pipe'); } + if (!process.env['VSCODE_GIT_ASKPASS_TYPE']) { + return fatal('Missing type'); + } + + if (process.env['VSCODE_GIT_ASKPASS_TYPE'] !== 'https' && process.env['VSCODE_GIT_ASKPASS_TYPE'] !== 'ssh') { + return fatal(`Invalid type: ${process.env['VSCODE_GIT_ASKPASS_TYPE']}`); + } + 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; - const request = argv[2]; - const host = argv[4].replace(/^["']+|["':]+$/g, ''); - const ipcClient = new IPCClient('askpass'); + const askpassType = process.env['VSCODE_GIT_ASKPASS_TYPE'] as 'https' | 'ssh'; - ipcClient.call({ request, host }).then(res => { + // HTTPS (username | password), SSH (passphrase | authenticity) + const request = askpassType === 'https' ? argv[2] : argv[3]; + + let host: string | undefined, + file: string | undefined, + fingerprint: string | undefined; + + if (askpassType === 'https') { + host = argv[4].replace(/^["']+|["':]+$/g, ''); + } + + if (askpassType === 'ssh') { + if (/passphrase/i.test(request)) { + // passphrase + file = argv[6].replace(/^["']+|["':]+$/g, ''); + } else { + // authenticity + host = argv[6].replace(/^["']+|["':]+$/g, ''); + fingerprint = argv[15]; + } + } + + const ipcClient = new IPCClient('askpass'); + ipcClient.call({ askpassType, request, host, file, fingerprint }).then(res => { fs.writeFileSync(output, res + '\n'); setTimeout(() => process.exit(0), 0); }).catch(err => fatal(err)); diff --git a/extensions/git/src/askpass.sh b/extensions/git/src/askpass.sh index 4536224764d..93a08c3896f 100755 --- a/extensions/git/src/askpass.sh +++ b/extensions/git/src/askpass.sh @@ -1,5 +1,5 @@ #!/bin/sh VSCODE_GIT_ASKPASS_PIPE=`mktemp` -ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $VSCODE_GIT_ASKPASS_EXTRA_ARGS $* +ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" VSCODE_GIT_ASKPASS_TYPE="https" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $VSCODE_GIT_ASKPASS_EXTRA_ARGS $* cat $VSCODE_GIT_ASKPASS_PIPE rm $VSCODE_GIT_ASKPASS_PIPE diff --git a/extensions/git/src/askpass.ts b/extensions/git/src/askpass.ts index cbf981eea19..6b0be6807dc 100644 --- a/extensions/git/src/askpass.ts +++ b/extensions/git/src/askpass.ts @@ -3,13 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, InputBoxOptions, Uri, Disposable, workspace } from 'vscode'; +import * as nls from 'vscode-nls'; +import { window, InputBoxOptions, Uri, Disposable, workspace, QuickPickOptions } from 'vscode'; import { IDisposable, EmptyDisposable, toDisposable } from './util'; import * as path from 'path'; import { IIPCHandler, IIPCServer } from './ipc/ipcServer'; import { CredentialsProvider, Credentials } from './api/git'; import { ITerminalEnvironmentProvider } from './terminal'; +const localize = nls.loadMessageBundle(); + export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider { private env: { [key: string]: string }; @@ -23,14 +26,22 @@ export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider { } this.env = { + // GIT_ASKPASS GIT_ASKPASS: path.join(__dirname, this.ipc ? 'askpass.sh' : 'askpass-empty.sh'), + // SSH_ASKPASS + SSH_ASKPASS: path.join(__dirname, this.ipc ? 'ssh-askpass.sh' : 'ssh-askpass-empty.sh'), + SSH_ASKPASS_REQUIRE: 'force', + // VSCODE_GIT_ASKPASS VSCODE_GIT_ASKPASS_NODE: process.execPath, VSCODE_GIT_ASKPASS_EXTRA_ARGS: (process.versions['electron'] && process.versions['microsoft-build']) ? '--ms-enable-electron-run-as-node' : '', VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js'), }; } - async handle({ request, host }: { request: string; host: string }): Promise { + async handle(payload: + { askpassType: 'https'; request: string; host: string } | + { askpassType: 'ssh'; request: string; host?: string; file?: string; fingerprint?: string } + ): Promise { const config = workspace.getConfiguration('git', null); const enabled = config.get('enabled'); @@ -38,6 +49,16 @@ export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider { return ''; } + // https + if (payload.askpassType === 'https') { + return await this.handleAskpass(payload.request, payload.host); + } + + // ssh + return await this.handleSSHAskpass(payload.request, payload.host, payload.file, payload.fingerprint); + } + + async handleAskpass(request: string, host: string): Promise { const uri = Uri.parse(host); const authority = uri.authority.replace(/^.*@/, ''); const password = /password/i.test(request); @@ -72,6 +93,33 @@ export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider { return await window.showInputBox(options) || ''; } + async handleSSHAskpass(request: string, host?: string, file?: string, fingerprint?: string): Promise { + // passphrase + if (/passphrase/i.test(request)) { + const options: InputBoxOptions = { + password: true, + placeHolder: localize('ssh passphrase', "Passphrase"), + prompt: `SSH Key: ${file}`, + ignoreFocusOut: true + }; + + return await window.showInputBox(options) || ''; + } + + // authenticity + const options: QuickPickOptions = { + canPickMany: false, + ignoreFocusOut: true, + placeHolder: localize('ssh authenticity prompt', "Are you sure you want to continue connecting?"), + title: localize('ssh authenticity title', "\"{0}\" has fingerprint \"{1}\"", host, fingerprint) + }; + const items = [ + localize('ssh authenticity prompt yes', "yes"), + localize('ssh authenticity prompt no', "no") + ]; + return await window.showQuickPick(items, options) ?? ''; + } + getEnv(): { [key: string]: string } { const config = workspace.getConfiguration('git'); return config.get('useIntegratedAskPass') ? this.env : {}; diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 22649e86fc7..b329a17c81d 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -5,11 +5,11 @@ import * as os from 'os'; import * as path from 'path'; -import { Command, commands, Disposable, LineChange, MessageOptions, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection, TextDocumentContentProvider, InputBoxValidationSeverity, TabInputText } from 'vscode'; +import { Command, commands, Disposable, LineChange, MessageOptions, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection, TextDocumentContentProvider, InputBoxValidationSeverity, TabInputText, TabInputTextMerge } from 'vscode'; import TelemetryReporter from '@vscode/extension-telemetry'; import * as nls from 'vscode-nls'; import { uniqueNamesGenerator, adjectives, animals, colors, NumberDictionary } from '@joaomoreno/unique-names-generator'; -import { Branch, ForcePushMode, GitErrorCodes, Ref, RefType, Status, CommitOptions, RemoteSourcePublisher, PostCommitCommand } from './api/git'; +import { Branch, ForcePushMode, GitErrorCodes, Ref, RefType, Status, CommitOptions, RemoteSourcePublisher } from './api/git'; import { Git, Stash } from './git'; import { Model } from './model'; import { Repository, Resource, ResourceGroupType } from './repository'; @@ -53,7 +53,7 @@ class CheckoutTagItem extends CheckoutItem { class CheckoutRemoteHeadItem extends CheckoutItem { - override get label(): string { return `$(git-branch) ${this.ref.name || this.shortCommit}`; } + override get label(): string { return `$(cloud) ${this.ref.name || this.shortCommit}`; } override get description(): string { return localize('remote branch at', "Remote branch at {0}", this.shortCommit); } @@ -408,7 +408,7 @@ export class CommandCenter { } } - @command('_git.openMergeEditor') + @command('git.openMergeEditor') async openMergeEditor(uri: unknown) { if (!(uri instanceof Uri)) { return; @@ -418,21 +418,25 @@ export class CommandCenter { return; } + const isRebasing = Boolean(repo.rebaseCommit); type InputData = { uri: Uri; title?: string; detail?: string; description?: string }; const mergeUris = toMergeUris(uri); - const ours: InputData = { uri: mergeUris.ours, title: localize('Yours', 'Yours') }; - const theirs: InputData = { uri: mergeUris.theirs, title: localize('Theirs', 'Theirs') }; + const current: InputData = { uri: mergeUris.ours, title: localize('Current', 'Current') }; + const incoming: InputData = { uri: mergeUris.theirs, title: localize('Incoming', 'Incoming') }; try { - const [head, mergeHead] = await Promise.all([repo.getCommit('HEAD'), repo.getCommit('MERGE_HEAD')]); + const [head, rebaseOrMergeHead] = await Promise.all([ + repo.getCommit('HEAD'), + isRebasing ? repo.getCommit('REBASE_HEAD') : repo.getCommit('MERGE_HEAD') + ]); // ours (current branch and commit) - ours.detail = head.refNames.map(s => s.replace(/^HEAD ->/, '')).join(', '); - ours.description = head.hash.substring(0, 7); + current.detail = head.refNames.map(s => s.replace(/^HEAD ->/, '')).join(', '); + current.description = '$(git-commit) ' + head.hash.substring(0, 7); // theirs - theirs.detail = mergeHead.refNames.join(', '); - theirs.description = mergeHead.hash.substring(0, 7); + incoming.detail = rebaseOrMergeHead.refNames.join(', '); + incoming.description = '$(git-commit) ' + rebaseOrMergeHead.hash.substring(0, 7); } catch (error) { // not so bad, can continue with just uris @@ -442,8 +446,8 @@ export class CommandCenter { const options = { base: mergeUris.base, - input1: theirs, - input2: ours, + input1: isRebasing ? current : incoming, + input2: isRebasing ? incoming : current, output: uri }; @@ -453,7 +457,7 @@ export class CommandCenter { ); } - async cloneRepository(url?: string, parentPath?: string, options: { recursive?: boolean } = {}): Promise { + async cloneRepository(url?: string, parentPath?: string, options: { recursive?: boolean; ref?: string } = {}): Promise { if (!url || typeof url !== 'string') { url = await pickRemoteSource({ providerLabel: provider => localize('clonefrom', "Clone from {0}", provider.name), @@ -465,7 +469,7 @@ export class CommandCenter { /* __GDPR__ "clone" : { "owner": "lszomoru", - "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The outcome of the git operation" } } */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'no_URL' }); @@ -484,6 +488,7 @@ export class CommandCenter { canSelectFolders: true, canSelectMany: false, defaultUri: Uri.file(defaultCloneDirectory), + title: localize('selectFolderTitle', "Choose a folder to clone {0} into", url), openLabel: localize('selectFolder', "Select Repository Location") }); @@ -491,7 +496,7 @@ export class CommandCenter { /* __GDPR__ "clone" : { "owner": "lszomoru", - "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The outcome of the git operation" } } */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'no_directory' }); @@ -514,6 +519,11 @@ export class CommandCenter { (progress, token) => this.git.clone(url!, { parentPath: parentPath!, progress, recursive: options.recursive }, token) ); + if (options.ref !== undefined) { + const repository = this.model.getRepository(Uri.file(repositoryPath)); + await repository?.checkout(options.ref); + } + const config = workspace.getConfiguration('git'); const openAfterClone = config.get<'always' | 'alwaysNewWindow' | 'whenNoFolderOpen' | 'prompt'>('openAfterClone'); @@ -550,8 +560,8 @@ export class CommandCenter { /* __GDPR__ "clone" : { "owner": "lszomoru", - "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "openFolder": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The outcome of the git operation" }, + "openFolder": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true, "comment": "Indicates whether the folder is opened following the clone operation" } } */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'success' }, { openFolder: action === PostCloneAction.Open || action === PostCloneAction.OpenNewWindow ? 1 : 0 }); @@ -570,7 +580,7 @@ export class CommandCenter { /* __GDPR__ "clone" : { "owner": "lszomoru", - "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The outcome of the git operation" } } */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'directory_not_empty' }); @@ -580,7 +590,7 @@ export class CommandCenter { /* __GDPR__ "clone" : { "owner": "lszomoru", - "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The outcome of the git operation" } } */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'error' }); @@ -591,8 +601,8 @@ export class CommandCenter { } @command('git.clone') - async clone(url?: string, parentPath?: string): Promise { - await this.cloneRepository(url, parentPath); + async clone(url?: string, parentPath?: string, options?: { ref?: string }): Promise { + await this.cloneRepository(url, parentPath, options); } @command('git.cloneRecursive') @@ -1099,21 +1109,26 @@ export class CommandCenter { return; } + const { activeTab } = window.tabGroups.activeTabGroup; + if (!activeTab) { + return; + } + + // make sure to save the merged document const doc = workspace.textDocuments.find(doc => doc.uri.toString() === uri.toString()); if (!doc) { console.log(`FAILED to accept merge because uri ${uri.toString()} doesn't match a document`); return; } + if (doc.isDirty) { + await doc.save(); + } - await doc.save(); - - // TODO@jrieken there isn't a `TabInputTextMerge` instance yet, till now the merge editor - // uses the `TabInputText` for the out-resource and we use that to identify and CLOSE the tab - // see https://github.com/microsoft/vscode/issues/153213 - const { activeTab } = window.tabGroups.activeTabGroup; + // find the merge editor tabs for the resource in question and close them all let didCloseTab = false; - if (activeTab && activeTab?.input instanceof TabInputText && activeTab.input.uri.toString() === uri.toString()) { - didCloseTab = await window.tabGroups.close(activeTab, true); + const mergeEditorTabs = window.tabGroups.all.map(group => group.tabs.filter(tab => tab.input instanceof TabInputTextMerge && tab.input.result.toString() === uri.toString())).flat(); + if (mergeEditorTabs.includes(activeTab)) { + didCloseTab = await window.tabGroups.close(mergeEditorTabs, true); } // Only stage if the merge editor has been successfully closed. That means all conflicts have been @@ -1124,6 +1139,51 @@ export class CommandCenter { } } + @command('git.runGitMerge') + async runGitMergeNoDiff3(): Promise { + await this.runGitMerge(false); + } + + @command('git.runGitMergeDiff3') + async runGitMergeDiff3(): Promise { + await this.runGitMerge(true); + } + + private async runGitMerge(diff3: boolean): Promise { + const { activeTab } = window.tabGroups.activeTabGroup; + if (!activeTab) { + return; + } + + const input = activeTab.input; + if (!(input instanceof TabInputTextMerge)) { + return; + } + + const result = await this.git.mergeFile({ + basePath: input.base.fsPath, + input1Path: input.input1.fsPath, + input2Path: input.input2.fsPath, + diff3, + }); + + const doc = workspace.textDocuments.find(doc => doc.uri.toString() === input.result.toString()); + if (!doc) { + return; + } + const e = new WorkspaceEdit(); + + e.replace( + input.result, + new Range( + new Position(0, 0), + new Position(doc.lineCount, 0), + ), + result + ); + await workspace.applyEdit(e); + } + private async _stageChanges(textEditor: TextEditor, changes: LineChange[]): Promise { const modifiedDocument = textEditor.document; const modifiedUri = modifiedDocument.uri; @@ -1443,7 +1503,7 @@ export class CommandCenter { private async smartCommit( repository: Repository, getCommitMessage: () => Promise, - opts?: CommitOptions + opts: CommitOptions ): Promise { const config = workspace.getConfiguration('git', Uri.file(repository.root)); let promptToSaveFilesBeforeCommit = config.get<'always' | 'staged' | 'never'>('promptToSaveFilesBeforeCommit'); @@ -1489,14 +1549,8 @@ export class CommandCenter { } } - if (!opts) { - opts = { all: noStagedChanges }; - } else if (!opts.all && noStagedChanges && !opts.empty) { - opts = { ...opts, all: true }; - } - // no changes, and the user has not configured to commit all in this case - if (!noUnstagedChanges && noStagedChanges && !enableSmartCommit && !opts.empty) { + if (!noUnstagedChanges && noStagedChanges && !enableSmartCommit && !opts.empty && !opts.all) { const suggestSmartCommit = config.get('suggestSmartCommit') === true; if (!suggestSmartCommit) { @@ -1520,6 +1574,12 @@ export class CommandCenter { } } + if (opts.all === undefined) { + opts = { ...opts, all: noStagedChanges }; + } else if (!opts.all && noStagedChanges && !opts.empty) { + opts = { ...opts, all: true }; + } + // enable signing of commits if configured opts.signCommit = enableCommitSigning; @@ -1549,6 +1609,8 @@ export class CommandCenter { // amend allows changing only the commit message && !opts.amend && !opts.empty + // rebase not in progress + && repository.rebaseCommit === undefined ) { const commitAnyway = localize('commit anyway', "Create Empty Commit"); const answer = await window.showInformationMessage(localize('no changes', "There are no changes to commit."), commitAnyway); @@ -1623,18 +1685,10 @@ export class CommandCenter { await repository.commit(message, opts); - const postCommitCommand = config.get<'none' | 'push' | 'sync'>('postCommitCommand'); - if ((opts.postCommitCommand === undefined && postCommitCommand === 'push') || opts.postCommitCommand === 'push') { - await this._push(repository, { pushType: PushType.Push }); - } - if ((opts.postCommitCommand === undefined && postCommitCommand === 'sync') || opts.postCommitCommand === 'sync') { - await this.sync(repository); - } - return true; } - private async commitWithAnyInput(repository: Repository, opts?: CommitOptions): Promise { + private async commitWithAnyInput(repository: Repository, opts: CommitOptions): Promise { const message = repository.inputBox.value; const root = Uri.file(repository.root); const config = workspace.getConfiguration('git', root); @@ -1677,7 +1731,7 @@ export class CommandCenter { } @command('git.commit', { repository: true }) - async commit(repository: Repository, postCommitCommand?: PostCommitCommand): Promise { + async commit(repository: Repository, postCommitCommand?: string): Promise { await this.commitWithAnyInput(repository, { postCommitCommand }); } @@ -1762,7 +1816,7 @@ export class CommandCenter { const shouldPrompt = config.get('confirmEmptyCommits') === true; if (shouldPrompt) { - const message = localize('confirm emtpy commit', "Are you sure you want to create an empty commit?"); + const message = localize('confirm empty commit', "Are you sure you want to create an empty commit?"); const yes = localize('yes', "Yes"); const neverAgain = localize('yes never again', "Yes, Don't Show Again"); const pick = await window.showWarningMessage(message, { modal: true }, yes, neverAgain); @@ -2148,6 +2202,11 @@ export class CommandCenter { await choice.run(repository); } + @command('git.mergeAbort', { repository: true }) + async abortMerge(repository: Repository): Promise { + await repository.mergeAbort(); + } + @command('git.rebase', { repository: true }) async rebase(repository: Repository): Promise { const config = workspace.getConfiguration('git'); @@ -2567,17 +2626,16 @@ export class CommandCenter { } } - if (rebase) { - await repository.syncRebase(HEAD); - } else { - await repository.sync(HEAD); - } + await repository.sync(HEAD, rebase); } @command('git.sync', { repository: true }) async sync(repository: Repository): Promise { + const config = workspace.getConfiguration('git', Uri.file(repository.root)); + const rebase = config.get('rebaseWhenSync', false) === true; + try { - await this._sync(repository, false); + await this._sync(repository, rebase); } catch (err) { if (/Cancelled/i.test(err && (err.message || err.stderr || ''))) { return; @@ -2590,13 +2648,16 @@ export class CommandCenter { @command('git._syncAll') async syncAll(): Promise { await Promise.all(this.model.repositories.map(async repository => { + const config = workspace.getConfiguration('git', Uri.file(repository.root)); + const rebase = config.get('rebaseWhenSync', false) === true; + const HEAD = repository.HEAD; if (!HEAD || !HEAD.upstream) { return; } - await repository.sync(HEAD); + await repository.sync(HEAD, rebase); })); } @@ -3056,7 +3117,7 @@ export class CommandCenter { /* __GDPR__ "git.command" : { "owner": "lszomoru", - "command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The command id of the command being executed" } } */ this.telemetryReporter.sendTelemetryEvent('git.command', { command: id }); diff --git a/extensions/git/src/editSessionIdentityProvider.ts b/extensions/git/src/editSessionIdentityProvider.ts new file mode 100644 index 00000000000..82b6953cf58 --- /dev/null +++ b/extensions/git/src/editSessionIdentityProvider.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 * as path from 'path'; +import * as vscode from 'vscode'; +import { Model } from './model'; + +export class GitEditSessionIdentityProvider implements vscode.EditSessionIdentityProvider, vscode.Disposable { + + private providerRegistration: vscode.Disposable; + + constructor(private model: Model) { + this.providerRegistration = vscode.workspace.registerEditSessionIdentityProvider('file', this); + } + + dispose() { + this.providerRegistration.dispose(); + } + + async provideEditSessionIdentity(workspaceFolder: vscode.WorkspaceFolder, _token: vscode.CancellationToken): Promise { + await this.model.openRepository(path.dirname(workspaceFolder.uri.fsPath)); + + const repository = this.model.getRepository(workspaceFolder.uri); + await repository?.status(); + + if (!repository || !repository?.HEAD?.upstream) { + return undefined; + } + + return JSON.stringify({ + remote: repository.remotes.find((remote) => remote.name === repository.HEAD?.upstream?.remote)?.pushUrl ?? null, + ref: repository.HEAD?.name ?? null, + sha: repository.HEAD?.commit ?? null, + }); + } +} diff --git a/extensions/git/src/git-editor.sh b/extensions/git/src/git-editor.sh index 1c45c2deac1..d7e0d2deece 100755 --- a/extensions/git/src/git-editor.sh +++ b/extensions/git/src/git-editor.sh @@ -1,4 +1,4 @@ #!/bin/sh ELECTRON_RUN_AS_NODE="1" \ -"$VSCODE_GIT_EDITOR_NODE" "$VSCODE_GIT_EDITOR_MAIN" $VSCODE_GIT_EDITOR_EXTRA_ARGS $@ +"$VSCODE_GIT_EDITOR_NODE" "$VSCODE_GIT_EDITOR_MAIN" $VSCODE_GIT_EDITOR_EXTRA_ARGS "$@" diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 18d66247661..9e351566f60 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -427,7 +427,7 @@ export class Git { let previousProgress = 0; lineStream.on('data', (line: string) => { - let match: RegExpMatchArray | null = null; + let match: RegExpExecArray | null = null; if (match = /Counting objects:\s*(\d+)%/i.exec(line)) { totalProgress = Math.floor(parseInt(match[1]) * 0.1); @@ -475,12 +475,13 @@ export class Git { const repoPath = path.normalize(result.stdout.trimLeft().replace(/[\r\n]+$/, '')); if (isWindows) { - // On Git 2.25+ if you call `rev-parse --show-toplevel` on a mapped drive, instead of getting the mapped drive path back, you get the UNC path for the mapped drive. - // So we will try to normalize it back to the mapped drive path, if possible + // On Git 2.25+ if you call `rev-parse --show-toplevel` on a mapped drive, instead of getting the mapped + // drive path back, you get the UNC path for the mapped drive. So we will try to normalize it back to the + // mapped drive path, if possible const repoUri = Uri.file(repoPath); const pathUri = Uri.file(repositoryPath); if (repoUri.authority.length !== 0 && pathUri.authority.length === 0) { - // eslint-disable-next-line code-no-look-behind-regex + // eslint-disable-next-line local/code-no-look-behind-regex const match = /(?<=^\/?)([a-zA-Z])(?=:\/)/.exec(pathUri.path); if (match !== null) { const [, letter] = match; @@ -648,6 +649,27 @@ export class Git { private log(output: string): void { this._onOutput.emit('log', output); } + + async mergeFile(options: { input1Path: string; input2Path: string; basePath: string; diff3?: boolean }): Promise { + const args = ['merge-file', '-p', options.input1Path, options.basePath, options.input2Path]; + if (options.diff3) { + args.push('--diff3'); + } else { + args.push('--no-diff3'); + } + + try { + const result = await this.exec('', args); + return result.stdout; + } catch (err) { + if (typeof err.stdout === 'string') { + // The merge had conflicts, stdout still contains the merged result (with conflict markers) + return err.stdout; + } else { + throw err; + } + } + } } export interface Commit { @@ -1087,7 +1109,7 @@ export class Repository { } if (!isText) { - const result = filetype(buffer); + const result = await filetype.fromBuffer(buffer); if (!result) { return { mimetype: 'application/octet-stream' }; @@ -1467,7 +1489,7 @@ export class Repository { const args = ['rebase', '--continue']; try { - await this.exec(args); + await this.exec(args, { env: { GIT_EDITOR: 'true' } }); } catch (commitErr) { await this.handleCommitError(commitErr); } @@ -1548,6 +1570,10 @@ export class Repository { } } + async mergeAbort(): Promise { + await this.exec(['merge', '--abort']); + } + async tag(name: string, message?: string): Promise { let args = ['tag']; diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index 6fbc88cc9fd..1542f5166f3 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -27,6 +27,8 @@ import { TerminalEnvironmentManager } from './terminal'; import { OutputChannelLogger } from './log'; import { createIPCServer, IPCServer } from './ipc/ipcServer'; import { GitEditor } from './gitEditor'; +import { GitPostCommitCommandsProvider } from './postCommitCommands'; +import { GitEditSessionIdentityProvider } from './editSessionIdentityProvider'; const deactivateTasks: { (): Promise }[] = []; @@ -113,10 +115,13 @@ async function createModel(context: ExtensionContext, outputChannelLogger: Outpu cc, new GitFileSystemProvider(model), new GitDecorations(model), - new GitProtocolHandler(), - new GitTimelineProvider(model, cc) + new GitTimelineProvider(model, cc), + new GitEditSessionIdentityProvider(model) ); + const postCommitCommandsProvider = new GitPostCommitCommandsProvider(); + model.registerPostCommitCommandsProvider(postCommitCommandsProvider); + checkGitVersion(info); return model; @@ -177,6 +182,8 @@ export async function _activate(context: ExtensionContext): Promise telemetryReporter.dispose()); diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 87c510b3b03..c10a9d6a193 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -13,12 +13,13 @@ import * as path from 'path'; import * as fs from 'fs'; import * as nls from 'vscode-nls'; import { fromGitUri } from './uri'; -import { APIState as State, CredentialsProvider, PushErrorHandler, PublishEvent, RemoteSourcePublisher } from './api/git'; +import { APIState as State, CredentialsProvider, PushErrorHandler, PublishEvent, RemoteSourcePublisher, PostCommitCommandsProvider } from './api/git'; import { Askpass } from './askpass'; import { IPushErrorHandlerRegistry } from './pushError'; import { ApiRepository } from './api/api1'; import { IRemoteSourcePublisherRegistry } from './remotePublisher'; import { OutputChannelLogger } from './log'; +import { IPostCommitCommandsProviderRegistry } from './postCommitCommands'; const localize = nls.loadMessageBundle(); @@ -50,7 +51,7 @@ interface OpenRepository extends Disposable { repository: Repository; } -export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerRegistry { +export class Model implements IRemoteSourcePublisherRegistry, IPostCommitCommandsProviderRegistry, IPushErrorHandlerRegistry { private _onDidOpenRepository = new EventEmitter(); readonly onDidOpenRepository: Event = this._onDidOpenRepository.event; @@ -105,6 +106,11 @@ export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerR private _onDidRemoveRemoteSourcePublisher = new EventEmitter(); readonly onDidRemoveRemoteSourcePublisher = this._onDidRemoveRemoteSourcePublisher.event; + private postCommitCommandsProviders = new Set(); + + private _onDidChangePostCommitCommandsProviders = new EventEmitter(); + readonly onDidChangePostCommitCommandsProviders = this._onDidChangePostCommitCommandsProviders.event; + private showRepoOnHomeDriveRootWarning = true; private pushErrorHandlers = new Set(); @@ -133,6 +139,18 @@ export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerR this.onDidChangeVisibleTextEditors(window.visibleTextEditors), this.scanWorkspaceFolders() ]); + + const config = workspace.getConfiguration('git'); + const autoRepositoryDetection = config.get('autoRepositoryDetection'); + + /* __GDPR__ + "git.repositoryInitialScan" : { + "owner": "lszomoru", + "autoRepositoryDetection": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Setting that controls the initial repository scan" }, + "repositoryCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "comment": "Number of repositories opened during initial repository scan" } + } + */ + this.telemetryReporter.sendTelemetryEvent('git.repositoryInitialScan', { autoRepositoryDetection: String(autoRepositoryDetection) }, { repositoryCount: this.openRepositories.length }); } /** @@ -305,7 +323,7 @@ export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerR @sequentialize async openRepository(repoPath: string): Promise { this.outputChannelLogger.logTrace(`Opening repository: ${repoPath}`); - if (this.getRepository(repoPath)) { + if (this.getRepositoryExact(repoPath)) { this.outputChannelLogger.logTrace(`Repository for path ${repoPath} already exists`); return; } @@ -341,7 +359,7 @@ export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerR const repositoryRoot = Uri.file(rawRoot).fsPath; this.outputChannelLogger.logTrace(`Repository root: ${repositoryRoot}`); - if (this.getRepository(repositoryRoot)) { + if (this.getRepositoryExact(repositoryRoot)) { this.outputChannelLogger.logTrace(`Repository for path ${repositoryRoot} already exists`); return; } @@ -369,7 +387,7 @@ export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerR } const dotGit = await this.git.getRepositoryDotGit(repositoryRoot); - const repository = new Repository(this.git.open(repositoryRoot, dotGit), this, this, this.globalState, this.outputChannelLogger, this.telemetryReporter); + const repository = new Repository(this.git.open(repositoryRoot, dotGit), this, this, this, this.globalState, this.outputChannelLogger, this.telemetryReporter); this.open(repository); repository.status(); // do not await this, we want SCM to know about the repo asap @@ -492,6 +510,12 @@ export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerR return liveRepository && liveRepository.repository; } + private getRepositoryExact(repoPath: string): Repository | undefined { + const openRepository = this.openRepositories + .find(r => pathEquals(r.repository.root, repoPath)); + return openRepository?.repository; + } + private getOpenRepository(repository: Repository): OpenRepository | undefined; private getOpenRepository(sourceControl: SourceControl): OpenRepository | undefined; private getOpenRepository(resourceGroup: SourceControlResourceGroup): OpenRepository | undefined; @@ -506,6 +530,10 @@ export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerR return this.openRepositories.filter(r => r.repository === hint)[0]; } + if (hint instanceof ApiRepository) { + return this.openRepositories.filter(r => r.repository === hint.repository)[0]; + } + if (typeof hint === 'string') { hint = Uri.file(hint); } @@ -582,6 +610,20 @@ export class Model implements IRemoteSourcePublisherRegistry, IPushErrorHandlerR return [...this.remoteSourcePublishers.values()]; } + registerPostCommitCommandsProvider(provider: PostCommitCommandsProvider): Disposable { + this.postCommitCommandsProviders.add(provider); + this._onDidChangePostCommitCommandsProviders.fire(); + + return toDisposable(() => { + this.postCommitCommandsProviders.delete(provider); + this._onDidChangePostCommitCommandsProviders.fire(); + }); + } + + getPostCommitCommandsProviders(): PostCommitCommandsProvider[] { + return [...this.postCommitCommandsProviders.values()]; + } + registerCredentialsProvider(provider: CredentialsProvider): Disposable { return this.askpass.registerCredentialsProvider(provider); } diff --git a/extensions/git/src/postCommitCommands.ts b/extensions/git/src/postCommitCommands.ts new file mode 100644 index 00000000000..1509aa35177 --- /dev/null +++ b/extensions/git/src/postCommitCommands.ts @@ -0,0 +1,202 @@ +/*--------------------------------------------------------------------------------------------- + * 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 'vscode-nls'; +import { commands, Disposable, Event, EventEmitter, Memento, Uri, workspace } from 'vscode'; +import { CommitCommand, PostCommitCommandsProvider } from './api/git'; +import { Operation, Repository } from './repository'; +import { ApiRepository } from './api/api1'; +import { dispose } from './util'; + +export interface IPostCommitCommandsProviderRegistry { + readonly onDidChangePostCommitCommandsProviders: Event; + + getPostCommitCommandsProviders(): PostCommitCommandsProvider[]; + registerPostCommitCommandsProvider(provider: PostCommitCommandsProvider): Disposable; +} + +const localize = nls.loadMessageBundle(); + +export class GitPostCommitCommandsProvider implements PostCommitCommandsProvider { + getCommands(apiRepository: ApiRepository): CommitCommand[] { + const config = workspace.getConfiguration('git', Uri.file(apiRepository.repository.root)); + + // Branch protection + const isBranchProtected = apiRepository.repository.isBranchProtected(); + const branchProtectionPrompt = config.get<'alwaysCommit' | 'alwaysCommitToNewBranch' | 'alwaysPrompt'>('branchProtectionPrompt')!; + const alwaysPrompt = isBranchProtected && branchProtectionPrompt === 'alwaysPrompt'; + const alwaysCommitToNewBranch = isBranchProtected && branchProtectionPrompt === 'alwaysCommitToNewBranch'; + + // Icon + const icon = alwaysPrompt ? '$(lock)' : alwaysCommitToNewBranch ? '$(git-branch)' : undefined; + + // Tooltip (default) + let pushCommandTooltip = !alwaysCommitToNewBranch ? + localize('scm button commit and push tooltip', "Commit & Push Changes") : + localize('scm button commit to new branch and push tooltip', "Commit to New Branch & Push Changes"); + + let syncCommandTooltip = !alwaysCommitToNewBranch ? + localize('scm button commit and sync tooltip', "Commit & Sync Changes") : + localize('scm button commit to new branch and sync tooltip', "Commit to New Branch & Synchronize Changes"); + + // Tooltip (in progress) + if (apiRepository.repository.operations.isRunning(Operation.Commit)) { + pushCommandTooltip = !alwaysCommitToNewBranch ? + localize('scm button committing and pushing tooltip', "Committing & Pushing Changes...") : + localize('scm button committing to new branch and pushing tooltip', "Committing to New Branch & Pushing Changes..."); + + syncCommandTooltip = !alwaysCommitToNewBranch ? + localize('scm button committing and syncing tooltip', "Committing & Synchronizing Changes...") : + localize('scm button committing to new branch and syncing tooltip', "Committing to New Branch & Synchronizing Changes..."); + } + + return [ + { + command: 'git.push', + title: localize('scm button commit and push title', "{0} Commit", icon ?? '$(arrow-up)'), + description: localize('scm button commit and push description', "{0} Commit & Push", icon ?? '$(arrow-up)'), + tooltip: pushCommandTooltip + }, + { + command: 'git.sync', + title: localize('scm button commit and sync title', "{0} Commit", icon ?? '$(sync)'), + description: localize('scm button commit and sync description', "{0} Commit & Sync", icon ?? '$(sync)'), + tooltip: syncCommandTooltip + }, + ]; + } +} + +export class CommitCommandsCenter { + + private _onDidChange = new EventEmitter(); + get onDidChange(): Event { return this._onDidChange.event; } + + private disposables: Disposable[] = []; + + constructor( + private readonly globalState: Memento, + private readonly repository: Repository, + private readonly postCommitCommandsProviderRegistry: IPostCommitCommandsProviderRegistry + ) { + const root = Uri.file(repository.root); + + const onRememberPostCommitCommandChange = async () => { + const config = workspace.getConfiguration('git', root); + if (!config.get('rememberPostCommitCommand')) { + await this.globalState.update(repository.root, undefined); + } + }; + this.disposables.push(workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('git.rememberPostCommitCommand', root)) { + onRememberPostCommitCommandChange(); + } + })); + onRememberPostCommitCommandChange(); + + this.disposables.push(postCommitCommandsProviderRegistry.onDidChangePostCommitCommandsProviders(() => this._onDidChange.fire())); + } + + getPrimaryCommand(): CommitCommand { + const allCommands = this.getSecondaryCommands().map(c => c).flat(); + const commandFromStorage = allCommands.find(c => c.arguments?.length === 2 && c.arguments[1] === this.getPostCommitCommandStringFromStorage()); + const commandFromSetting = allCommands.find(c => c.arguments?.length === 2 && c.arguments[1] === this.getPostCommitCommandStringFromSetting()); + + return commandFromStorage ?? commandFromSetting ?? this.getCommitCommand(); + } + + getSecondaryCommands(): CommitCommand[][] { + const commandGroups: CommitCommand[][] = []; + + for (const provider of this.postCommitCommandsProviderRegistry.getPostCommitCommandsProviders()) { + const commands = provider.getCommands(new ApiRepository(this.repository)); + commandGroups.push((commands ?? []).map(c => { + return { command: 'git.commit', title: c.title, description: c.description, tooltip: c.tooltip, arguments: [this.repository.sourceControl, c.command] }; + })); + } + + if (commandGroups.length > 0) { + commandGroups[0].splice(0, 0, this.getCommitCommand()); + } + + return commandGroups; + } + + async executePostCommitCommand(command: string | undefined): Promise { + if (command === undefined) { + // Commit WAS NOT initiated using the action button (ex: keybinding, toolbar action, + // command palette) so we have to honour the default post commit command (memento/setting). + const primaryCommand = this.getPrimaryCommand(); + command = primaryCommand.arguments?.length === 2 ? primaryCommand.arguments[1] : ''; + } + + if (command?.length) { + await commands.executeCommand(command, new ApiRepository(this.repository)); + } + + await this.savePostCommitCommand(command); + } + + private getCommitCommand(): CommitCommand { + const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); + + // Branch protection + const isBranchProtected = this.repository.isBranchProtected(); + const branchProtectionPrompt = config.get<'alwaysCommit' | 'alwaysCommitToNewBranch' | 'alwaysPrompt'>('branchProtectionPrompt')!; + const alwaysPrompt = isBranchProtected && branchProtectionPrompt === 'alwaysPrompt'; + const alwaysCommitToNewBranch = isBranchProtected && branchProtectionPrompt === 'alwaysCommitToNewBranch'; + + // Icon + const icon = alwaysPrompt ? '$(lock)' : alwaysCommitToNewBranch ? '$(git-branch)' : undefined; + + // Tooltip (default) + let tooltip = !alwaysCommitToNewBranch ? + localize('scm button commit tooltip', "Commit Changes") : + localize('scm button commit to new branch tooltip', "Commit Changes to New Branch"); + + // Tooltip (in progress) + if (this.repository.operations.isRunning(Operation.Commit)) { + tooltip = !alwaysCommitToNewBranch ? + localize('scm button committing tooltip', "Committing Changes...") : + localize('scm button committing to new branch tooltip', "Committing Changes to New Branch..."); + } + + return { command: 'git.commit', title: localize('scm button commit title', "{0} Commit", icon ?? '$(check)'), tooltip, arguments: [this.repository.sourceControl, ''] }; + } + + private getPostCommitCommandStringFromSetting(): string | undefined { + const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); + const postCommitCommandSetting = config.get('postCommitCommand'); + + return postCommitCommandSetting === 'push' || postCommitCommandSetting === 'sync' ? `git.${postCommitCommandSetting}` : undefined; + } + + private getPostCommitCommandStringFromStorage(): string | undefined { + if (!this.isRememberPostCommitCommandEnabled()) { + return undefined; + } + + return this.globalState.get(this.repository.root); + } + + private isRememberPostCommitCommandEnabled(): boolean { + const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); + return config.get('rememberPostCommitCommand') === true; + } + + private async savePostCommitCommand(command: string | undefined): Promise { + if (!this.isRememberPostCommitCommandEnabled()) { + return; + } + + command = command !== '' ? command : undefined; + await this.globalState.update(this.repository.root, command); + this._onDidChange.fire(); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + } +} diff --git a/extensions/git/src/protocolHandler.ts b/extensions/git/src/protocolHandler.ts index 33decfe1846..3dccfa48665 100644 --- a/extensions/git/src/protocolHandler.ts +++ b/extensions/git/src/protocolHandler.ts @@ -3,9 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); + import { UriHandler, Uri, window, Disposable, commands } from 'vscode'; import { dispose } from './util'; import * as querystring from 'querystring'; +import { OutputChannelLogger } from './log'; const schemes = new Set(['file', 'git', 'http', 'https', 'ssh']); @@ -13,26 +17,34 @@ export class GitProtocolHandler implements UriHandler { private disposables: Disposable[] = []; - constructor() { + constructor(private readonly outputChannelLogger: OutputChannelLogger) { this.disposables.push(window.registerUriHandler(this)); } handleUri(uri: Uri): void { + this.outputChannelLogger.logInfo(`GitProtocolHandler.handleUri(${uri.toString()})`); + switch (uri.path) { case '/clone': this.clone(uri); } } - private clone(uri: Uri): void { + private async clone(uri: Uri): Promise { const data = querystring.parse(uri.query); + const ref = data.ref; if (!data.url) { - console.warn('Failed to open URI:', uri); + this.outputChannelLogger.logWarning('Failed to open URI:' + uri.toString()); return; } if (Array.isArray(data.url) && data.url.length === 0) { - console.warn('Failed to open URI:', uri); + this.outputChannelLogger.logWarning('Failed to open URI:' + uri.toString()); + return; + } + + if (ref !== undefined && typeof ref !== 'string') { + this.outputChannelLogger.logWarning('Failed to open URI:' + uri.toString()); return; } @@ -52,11 +64,26 @@ export class GitProtocolHandler implements UriHandler { } } catch (ex) { - console.warn('Invalid URI:', uri); + this.outputChannelLogger.logWarning('Invalid URI:' + uri.toString()); return; } - commands.executeCommand('git.clone', cloneUri.toString(true)); + if (!(await commands.getCommands(true)).includes('git.clone')) { + this.outputChannelLogger.logError('Could not complete git clone operation as git installation was not found.'); + + const errorMessage = localize('no git', 'Could not clone your repository as Git is not installed.'); + const downloadGit = localize('download git', 'Download Git'); + + if (await window.showErrorMessage(errorMessage, { modal: true }, downloadGit) === downloadGit) { + commands.executeCommand('vscode.open', Uri.parse('https://aka.ms/vscode-download-git')); + } + + return; + } else { + const cloneTarget = cloneUri.toString(true); + this.outputChannelLogger.logInfo(`Executing git.clone for ${cloneTarget}`); + commands.executeCommand('git.clone', cloneTarget, undefined, { ref: ref }); + } } dispose(): void { diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index eb0de19bcf6..d95ed760807 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -22,6 +22,7 @@ import { IPushErrorHandlerRegistry } from './pushError'; import { ApiRepository } from './api/api1'; import { IRemoteSourcePublisherRegistry } from './remotePublisher'; import { ActionButtonCommand } from './actionButton'; +import { IPostCommitCommandsProviderRegistry, CommitCommandsCenter } from './postCommitCommands'; const timeout = (millis: number) => new Promise(c => setTimeout(c, millis)); @@ -86,6 +87,7 @@ export class Resource implements SourceControlResourceState { return this.resources[1]; } + @memoize get command(): Command { return this._commandResolver.resolveDefaultCommand(this); } @@ -334,6 +336,7 @@ export const enum Operation { RenameBranch = 'RenameBranch', DeleteRef = 'DeleteRef', Merge = 'Merge', + MergeAbort = 'MergeAbort', Rebase = 'Rebase', Ignore = 'Ignore', Tag = 'Tag', @@ -616,9 +619,9 @@ class ResourceCommandResolver { if (!resource.leftUri) { const bothModified = resource.type === Status.BOTH_MODIFIED; - if (resource.rightUri && bothModified && workspace.getConfiguration('git').get('mergeEditor', false)) { + if (resource.rightUri && workspace.getConfiguration('git').get('mergeEditor', false) && (bothModified || resource.type === Status.BOTH_ADDED)) { return { - command: '_git.openMergeEditor', + command: 'git.openMergeEditor', title: localize('open.merge', "Open Merge"), arguments: [resource.rightUri] }; @@ -830,14 +833,33 @@ export class Repository implements Disposable { this.inputBox.value = rebaseCommit.message; } + const shouldUpdateContext = !!this._rebaseCommit !== !!rebaseCommit; this._rebaseCommit = rebaseCommit; - commands.executeCommand('setContext', 'gitRebaseInProgress', !!this._rebaseCommit); + + if (shouldUpdateContext) { + commands.executeCommand('setContext', 'gitRebaseInProgress', !!this._rebaseCommit); + } } get rebaseCommit(): Commit | undefined { return this._rebaseCommit; } + private _mergeInProgress: boolean = false; + + set mergeInProgress(value: boolean) { + if (this._mergeInProgress === value) { + return; + } + + this._mergeInProgress = value; + commands.executeCommand('setContext', 'gitMergeInProgress', value); + } + + get mergeInProgress() { + return this._mergeInProgress; + } + private _operations = new OperationsImpl(); get operations(): Operations { return this._operations; } @@ -869,6 +891,7 @@ export class Repository implements Disposable { private didWarnAboutLimit = false; private isBranchProtectedMatcher: picomatch.Matcher | undefined; + private commitCommandCenter: CommitCommandsCenter; private resourceCommandResolver = new ResourceCommandResolver(this); private disposables: Disposable[] = []; @@ -876,6 +899,7 @@ export class Repository implements Disposable { private readonly repository: BaseRepository, private pushErrorHandlerRegistry: IPushErrorHandlerRegistry, remoteSourcePublisherRegistry: IRemoteSourcePublisherRegistry, + postCommitCommandsProviderRegistry: IPostCommitCommandsProviderRegistry, globalState: Memento, outputChannelLogger: OutputChannelLogger, private telemetryReporter: TelemetryReporter @@ -946,7 +970,6 @@ export class Repository implements Disposable { || e.affectsConfiguration('git.untrackedChanges', root) || e.affectsConfiguration('git.ignoreSubmodules', root) || e.affectsConfiguration('git.openDiffOnClick', root) - || e.affectsConfiguration('git.rebaseWhenSync', root) || e.affectsConfiguration('git.showActionButton', root) )(this.updateModelState, this, this.disposables); @@ -997,7 +1020,10 @@ export class Repository implements Disposable { statusBar.onDidChange(() => this._sourceControl.statusBarCommands = statusBar.commands, null, this.disposables); this._sourceControl.statusBarCommands = statusBar.commands; - const actionButton = new ActionButtonCommand(this); + this.commitCommandCenter = new CommitCommandsCenter(globalState, this, postCommitCommandsProviderRegistry); + this.disposables.push(this.commitCommandCenter); + + const actionButton = new ActionButtonCommand(this, this.commitCommandCenter); this.disposables.push(actionButton); actionButton.onDidChange(() => this._sourceControl.actionButton = actionButton.button); this._sourceControl.actionButton = actionButton.button; @@ -1249,6 +1275,9 @@ export class Repository implements Disposable { await this.repository.commit(message, opts); this.closeDiffEditors(indexResources, workingGroupResources); }); + + // Execute post-commit command + await this.commitCommandCenter.executePostCommitCommand(opts.postCommitCommand); } } @@ -1356,6 +1385,10 @@ export class Repository implements Disposable { await this.run(Operation.Merge, () => this.repository.merge(ref)); } + async mergeAbort(): Promise { + await this.run(Operation.MergeAbort, async () => await this.repository.mergeAbort()); + } + async rebase(branch: string): Promise { await this.run(Operation.Rebase, () => this.repository.rebase(branch)); } @@ -1508,13 +1541,8 @@ export class Repository implements Disposable { } @throttle - sync(head: Branch): Promise { - return this._sync(head, false); - } - - @throttle - async syncRebase(head: Branch): Promise { - return this._sync(head, true); + sync(head: Branch, rebase: boolean): Promise { + return this._sync(head, rebase); } private async _sync(head: Branch, rebase: boolean): Promise { @@ -1892,18 +1920,21 @@ export class Repository implements Disposable { const limit = scopedConfig.get('statusLimit', 10000); + const start = new Date().getTime(); const { status, statusLength, didHitLimit } = await this.repository.getStatus({ limit, ignoreSubmodules, untrackedChanges }); + const totalTime = new Date().getTime() - start; if (didHitLimit) { /* __GDPR__ "statusLimit" : { "owner": "lszomoru", - "ignoreSubmodules": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "limit": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "statusLength": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + "ignoreSubmodules": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Setting indicating whether submodules are ignored" }, + "limit": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "comment": "Setting indicating the limit of status entries" }, + "statusLength": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "comment": "Total number of status entries" }, + "totalTime": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "comment": "Total number of ms the operation took" } } */ - this.telemetryReporter.sendTelemetryEvent('statusLimit', { ignoreSubmodules: String(ignoreSubmodules) }, { limit, statusLength }); + this.telemetryReporter.sendTelemetryEvent('statusLimit', { ignoreSubmodules: String(ignoreSubmodules) }, { limit, statusLength, totalTime }); } const config = workspace.getConfiguration('git'); @@ -1947,6 +1978,22 @@ export class Repository implements Disposable { } } + if (totalTime > 5000) { + /* __GDPR__ + "statusSlow" : { + "owner": "digitarald", + "comment": "Reports when git status is slower than 5s", + "expiration": "1.73", + "ignoreSubmodules": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Setting indicating whether submodules are ignored" }, + "didHitLimit": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Total number of status entries" }, + "didWarnAboutLimit": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "True when the user was warned about slow git status" }, + "statusLength": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "comment": "Total number of status entries" }, + "totalTime": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "comment": "Total number of ms the operation took" } + } + */ + this.telemetryReporter.sendTelemetryEvent('statusSlow', { ignoreSubmodules: String(ignoreSubmodules), didHitLimit: String(didHitLimit), didWarnAboutLimit: String(this.didWarnAboutLimit) }, { statusLength, totalTime }); + } + let HEAD: Branch | undefined; try { @@ -1967,13 +2014,14 @@ export class Repository implements Disposable { if (sort !== 'alphabetically' && sort !== 'committerdate') { sort = 'alphabetically'; } - const [refs, remotes, submodules, rebaseCommit] = await Promise.all([this.repository.getRefs({ sort }), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit()]); + const [refs, remotes, submodules, rebaseCommit, mergeInProgress] = await Promise.all([this.repository.getRefs({ sort }), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit(), this.isMergeInProgress()]); this._HEAD = HEAD; this._refs = refs!; this._remotes = remotes!; this._submodules = submodules!; this.rebaseCommit = rebaseCommit; + this.mergeInProgress = mergeInProgress; const index: Resource[] = []; const workingTree: Resource[] = []; @@ -2032,6 +2080,9 @@ export class Repository implements Disposable { // set count badge this.setCountBadge(); + // set mergeChanges context + commands.executeCommand('setContext', 'git.mergeChanges', merge.map(item => item.resourceUri)); + this._onDidChangeStatus.fire(); this._sourceControl.commitTemplate = await this.getInputTemplate(); @@ -2084,6 +2135,11 @@ export class Repository implements Disposable { } } + private isMergeInProgress(): Promise { + const mergeHeadPath = path.join(this.repository.root, '.git', 'MERGE_HEAD'); + return new Promise(resolve => fs.exists(mergeHeadPath, resolve)); + } + private async maybeAutoStash(runOperation: () => Promise): Promise { const config = workspace.getConfiguration('git', Uri.file(this.root)); const shouldAutoStash = config.get('autoStash') diff --git a/extensions/git/src/ssh-askpass-empty.sh b/extensions/git/src/ssh-askpass-empty.sh new file mode 100755 index 00000000000..8fb014e5cc9 --- /dev/null +++ b/extensions/git/src/ssh-askpass-empty.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo '' \ No newline at end of file diff --git a/extensions/git/src/ssh-askpass.sh b/extensions/git/src/ssh-askpass.sh new file mode 100755 index 00000000000..dca45bc8404 --- /dev/null +++ b/extensions/git/src/ssh-askpass.sh @@ -0,0 +1,5 @@ +#!/bin/sh +VSCODE_GIT_ASKPASS_PIPE=`mktemp` +ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" VSCODE_GIT_ASKPASS_TYPE="ssh" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $VSCODE_GIT_ASKPASS_EXTRA_ARGS $* +cat $VSCODE_GIT_ASKPASS_PIPE +rm $VSCODE_GIT_ASKPASS_PIPE diff --git a/extensions/git/src/statusbar.ts b/extensions/git/src/statusbar.ts index 68a9c91eb3a..bfb61d4266c 100644 --- a/extensions/git/src/statusbar.ts +++ b/extensions/git/src/statusbar.ts @@ -145,10 +145,7 @@ class SyncStatusBar { text += this.repository.syncLabel; } - const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); - const rebaseWhenSync = config.get('rebaseWhenSync'); - - command = rebaseWhenSync ? 'git.syncRebase' : 'git.sync'; + command = 'git.sync'; tooltip = this.repository.syncTooltip; } else { icon = '$(cloud-upload)'; diff --git a/extensions/git/src/typings/vscode.proposed.contribEditSessions.d.ts b/extensions/git/src/typings/vscode.proposed.contribEditSessions.d.ts new file mode 100644 index 00000000000..e4d10f273f9 --- /dev/null +++ b/extensions/git/src/typings/vscode.proposed.contribEditSessions.d.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + // https://github.com/microsoft/vscode/issues/157734 + + export namespace workspace { + /** + * + * @param scheme The URI scheme that this provider can provide edit session identities for. + * @param provider A provider which can convert URIs for workspace folders of scheme @param scheme to + * an edit session identifier which is stable across machines. This enables edit sessions to be resolved. + */ + export function registerEditSessionIdentityProvider(scheme: string, provider: EditSessionIdentityProvider): Disposable; + } + + export interface EditSessionIdentityProvider { + /** + * + * @param workspaceFolder The workspace folder to provide an edit session identity for. + * @param token A cancellation token for the request. + * @returns An string representing the edit session identity for the requested workspace folder. + */ + provideEditSessionIdentity(workspaceFolder: WorkspaceFolder, token: CancellationToken): ProviderResult; + } +} diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index e36cebf97cf..0c771ac008f 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -314,6 +314,13 @@ export function pathEquals(a: string, b: string): boolean { * casing. */ export function relativePath(from: string, to: string): string { + // On Windows, there are cases in which `from` is a path that contains a trailing `\` character + // (ex: C:\, \\server\folder\) due to the implementation of `path.normalize()`. This behavior is + // by design as documented in https://github.com/nodejs/node/issues/1765. + if (isWindows) { + from = from.replace(/\\$/, ''); + } + if (isDescendant(from, to) && from.length < to.length) { return to.substring(from.length + 1); } diff --git a/extensions/git/tsconfig.json b/extensions/git/tsconfig.json index 13997275056..c62c25401f2 100644 --- a/extensions/git/tsconfig.json +++ b/extensions/git/tsconfig.json @@ -14,7 +14,7 @@ "../../src/vscode-dts/vscode.proposed.scmActionButton.d.ts", "../../src/vscode-dts/vscode.proposed.scmSelectedProvider.d.ts", "../../src/vscode-dts/vscode.proposed.scmValidation.d.ts", - "../../src/vscode-dts/vscode.proposed.tabs.d.ts", + "../../src/vscode-dts/vscode.proposed.tabInputTextMerge.d.ts", "../../src/vscode-dts/vscode.proposed.timeline.d.ts", "../types/lib.textEncoder.d.ts" ] diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index ef4044fdd1c..502b35d9c38 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -7,6 +7,47 @@ resolved "https://registry.yarnpkg.com/@joaomoreno/unique-names-generator/-/unique-names-generator-5.0.0.tgz#a67fe66e3d825c929fc97abfdf17fd80a72beab0" integrity sha512-3kP6z7aoGEoM3tvhTBZioYa1QFkovOU8uxAlVclnZlXivwF/WTE5EcOzvoDdM+jtjJyWvCMDR1Q4RBjDqupD3A== +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + +"@tokenizer/token@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276" + integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A== + "@types/byline@4.2.31": version "4.2.31" resolved "https://registry.yarnpkg.com/@types/byline/-/byline-4.2.31.tgz#0e61fcb9c03e047d21c4496554c7116297ab60cd" @@ -14,13 +55,6 @@ dependencies: "@types/node" "*" -"@types/file-type@^5.2.1": - version "5.2.1" - resolved "https://registry.yarnpkg.com/@types/file-type/-/file-type-5.2.1.tgz#e7af49e08187b6b7598509c5e416669d25fa3461" - integrity sha512-Im0cJaIPJbbpuW91OrjXnqWPZCJK/tcFy2cFX+1qjG1gubgVZPPO9OVsTVAjotN4I1E6FAV0eIqt+rR8Y1c3iA== - dependencies: - "@types/node" "*" - "@types/mocha@^9.1.1": version "9.1.1" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" @@ -46,10 +80,13 @@ resolved "https://registry.yarnpkg.com/@types/which/-/which-1.0.28.tgz#016e387629b8817bed653fe32eab5d11279c8df6" integrity sha1-AW44dim4gXvtZT/jLqtdESecjfY= -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" "@vscode/iconv-lite-umd@0.7.0": version "0.7.0" @@ -61,10 +98,24 @@ byline@^5.0.0: resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= -file-type@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-7.2.0.tgz#113cfed52e1d6959ab80248906e2f25a8cdccb74" - integrity sha1-ETz+1S4daVmrgCSJBuLyWozcy3Q= +file-type@16.5.4: + version "16.5.4" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-16.5.4.tgz#474fb4f704bee427681f98dd390058a172a6c2fd" + integrity sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw== + dependencies: + readable-web-to-node-stream "^3.0.0" + strtok3 "^6.2.4" + token-types "^4.1.1" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== isexe@^2.0.0: version "2.0.0" @@ -76,15 +127,69 @@ jschardet@3.0.0: resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882" integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ== +peek-readable@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-4.1.0.tgz#4ece1111bf5c2ad8867c314c81356847e8a62e72" + integrity sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg== + picomatch@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -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== +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-web-to-node-stream@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb" + integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw== + dependencies: + readable-stream "^3.6.0" + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strtok3@^6.2.4: + version "6.3.0" + resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-6.3.0.tgz#358b80ffe6d5d5620e19a073aa78ce947a90f9a0" + integrity sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw== + dependencies: + "@tokenizer/token" "^0.3.0" + peek-readable "^4.1.0" + +token-types@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/token-types/-/token-types-4.2.0.tgz#b66bc3d67420c6873222a424eee64a744f4c2f13" + integrity sha512-P0rrp4wUpefLncNamWIef62J0v0kQR/GfDVji9WKY7GDCWy5YbVSrKUTam07iWPZQGy0zWNOfstYTykMmPNR7w== + dependencies: + "@tokenizer/token" "^0.3.0" + ieee754 "^1.2.1" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-uri@^2.0.0: version "2.0.0" diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index 78094e3c5f5..d9ccdc42d4c 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -48,7 +48,7 @@ } } }, - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "main": "./out/extension.js", "browser": "./dist/browser/extension.js", "scripts": { @@ -61,8 +61,8 @@ "dependencies": { "node-fetch": "2.6.7", "uuid": "8.1.0", - "@vscode/extension-telemetry": "0.6.1", - "vscode-nls": "^5.0.0", + "@vscode/extension-telemetry": "0.6.2", + "vscode-nls": "^5.1.0", "vscode-tas-client": "^0.1.47" }, "devDependencies": { diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts index 6816d9d992e..1614794fcb0 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -243,7 +243,7 @@ export class GitHubServer implements IGitHubServer { try { return await Promise.race([ codeExchangePromise.promise, - new Promise((_, reject) => setTimeout(() => reject('Cancelled'), 60000)), + new Promise((_, reject) => setTimeout(() => reject('Timed out'), 300_000)), // 5min timeout promiseFromEvent(token.onCancellationRequested, (_, __, reject) => { reject('User Cancelled'); }).promise ]); } finally { @@ -276,7 +276,7 @@ export class GitHubServer implements IGitHubServer { vscode.env.openExternal(vscode.Uri.parse(`http://127.0.0.1:${port}/signin?nonce=${encodeURIComponent(server.nonce)}`)); const { code } = await Promise.race([ server.waitForOAuthResponse(), - new Promise((_, reject) => setTimeout(() => reject('Cancelled'), 60000)), + new Promise((_, reject) => setTimeout(() => reject('Timed out'), 300_000)), // 5min timeout promiseFromEvent(token.onCancellationRequested, (_, __, reject) => { reject('User Cancelled'); }).promise ]); codeToExchange = code; diff --git a/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock index a390930318e..6ebb79992dc 100644 --- a/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -2,6 +2,42 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node-fetch@^2.5.7": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" @@ -25,10 +61,13 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.0.tgz#165aae4819ad2174a17476dbe66feebd549556c0" integrity sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" asynckit@^0.4.0: version "0.4.0" @@ -104,10 +143,10 @@ uuid@8.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d" integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-tas-client@^0.1.47: version "0.1.47" diff --git a/extensions/github/package.json b/extensions/github/package.json index fb33fbaf3a5..5f0e5a40245 100644 --- a/extensions/github/package.json +++ b/extensions/github/package.json @@ -26,7 +26,8 @@ } }, "enabledApiProposals": [ - "contribShareMenu" + "contribShareMenu", + "contribEditSessions" ], "contributes": { "commands": [ @@ -37,10 +38,21 @@ { "command": "github.copyVscodeDevLink", "title": "Copy vscode.dev Link" - }, - { - "command": "github.copyVscodeDevLinkFile", - "title": "Copy vscode.dev Link" + }, + { + "command": "github.copyVscodeDevLinkFile", + "title": "Copy vscode.dev Link" + }, + { + "command": "github.openOnVscodeDev", + "title": "Open on vscode.dev", + "icon": "$(globe)" + } + ], + "continueEditSession": [ + { + "command": "github.openOnVscodeDev", + "when": "github.hasGitHubRepo" } ], "menus": { @@ -56,6 +68,10 @@ { "command": "github.copyVscodeDevLinkFile", "when": "false" + }, + { + "command": "github.openOnVscodeDev", + "when": "false" } ], "file/share": [ @@ -115,9 +131,9 @@ "watch": "gulp watch-extension:github" }, "dependencies": { - "@octokit/rest": "^18.0.1", + "@octokit/rest": "19.0.4", "tunnel": "^0.0.6", - "vscode-nls": "^4.1.2" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/github/package.nls.json b/extensions/github/package.nls.json index b43271a87a0..4e9bdab9dfa 100644 --- a/extensions/github/package.nls.json +++ b/extensions/github/package.nls.json @@ -6,6 +6,8 @@ "welcome.publishFolder": { "message": "You can also directly publish this folder to a GitHub repository. Once published, you'll have access to source control features powered by git and GitHub.\n[$(github) Publish to GitHub](command:github.publish)", "comment": [ + "{Locked='$(github)'}", + "Do not translate '$(github)'. It will be rendered as an icon", "{Locked='](command:github.publish'}", "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code", "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links" @@ -14,6 +16,8 @@ "welcome.publishWorkspaceFolder": { "message": "You can also directly publish a workspace folder to a GitHub repository. Once published, you'll have access to source control features powered by git and GitHub.\n[$(github) Publish to GitHub](command:github.publish)", "comment": [ + "{Locked='$(github)'}", + "Do not translate '$(github)'. It will be rendered as an icon", "{Locked='](command:github.publish'}", "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code", "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links" diff --git a/extensions/github/src/commands.ts b/extensions/github/src/commands.ts index 8c68f36bfc6..d46bd50e454 100644 --- a/extensions/github/src/commands.ts +++ b/extensions/github/src/commands.ts @@ -7,11 +7,15 @@ import * as vscode from 'vscode'; import { API as GitAPI } from './typings/git'; import { publishRepository } from './publish'; import { DisposableStore } from './util'; -import { getPermalink } from './links'; +import { getLink } from './links'; + +function getVscodeDevHost(): string { + return `https://${vscode.env.appName.toLowerCase().includes('insiders') ? 'insiders.' : ''}vscode.dev/github`; +} async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) { try { - const permalink = getPermalink(gitAPI, useSelection, 'https://vscode.dev/github'); + const permalink = getLink(gitAPI, useSelection, getVscodeDevHost()); if (permalink) { return vscode.env.clipboard.writeText(permalink); } @@ -20,6 +24,16 @@ async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) { } } +async function openVscodeDevLink(gitAPI: GitAPI): Promise { + try { + const headlink = getLink(gitAPI, true, getVscodeDevHost(), 'headlink'); + return headlink ? vscode.Uri.parse(headlink) : undefined; + } catch (err) { + vscode.window.showErrorMessage(err.message); + return undefined; + } +} + export function registerCommands(gitAPI: GitAPI): vscode.Disposable { const disposables = new DisposableStore(); @@ -39,5 +53,9 @@ export function registerCommands(gitAPI: GitAPI): vscode.Disposable { return copyVscodeDevLink(gitAPI, false); })); + disposables.add(vscode.commands.registerCommand('github.openOnVscodeDev', async () => { + return openVscodeDevLink(gitAPI); + })); + return disposables; } diff --git a/extensions/github/src/links.ts b/extensions/github/src/links.ts index a025c79a804..00a2354645b 100644 --- a/extensions/github/src/links.ts +++ b/extensions/github/src/links.ts @@ -22,14 +22,50 @@ export function getRepositoryForFile(gitAPI: GitAPI, file: vscode.Uri): Reposito return undefined; } -function getFileAndPosition(): { uri: vscode.Uri | undefined; range: vscode.Range | undefined } { +enum LinkType { + File = 1, + Notebook = 2 +} + +interface IFilePosition { + type: LinkType.File; + uri: vscode.Uri; + range: vscode.Range | undefined; +} + +interface INotebookPosition { + type: LinkType.Notebook; + uri: vscode.Uri; + cellIndex: number; + range: vscode.Range | undefined; +} + +function getFileAndPosition(): IFilePosition | INotebookPosition | undefined { let uri: vscode.Uri | undefined; let range: vscode.Range | undefined; if (vscode.window.activeTextEditor) { uri = vscode.window.activeTextEditor.document.uri; - range = vscode.window.activeTextEditor.selection; + + if (uri.scheme === 'vscode-notebook-cell' && vscode.window.activeNotebookEditor?.notebook.uri.fsPath === uri.fsPath) { + // if the active editor is a notebook editor and the focus is inside any a cell text editor + // generate deep link for text selection for the notebook cell. + const cell = vscode.window.activeNotebookEditor.notebook.getCells().find(cell => cell.document.uri.fragment === uri?.fragment); + const cellIndex = cell?.index ?? vscode.window.activeNotebookEditor.selection.start; + const range = cell !== undefined ? vscode.window.activeTextEditor.selection : undefined; + return { type: LinkType.Notebook, uri, cellIndex, range }; + } else { + // the active editor is a text editor + range = vscode.window.activeTextEditor.selection; + return { type: LinkType.File, uri, range }; + } } - return { uri, range }; + + if (vscode.window.activeNotebookEditor) { + // if the active editor is a notebook editor but the focus is not inside any cell text editor, generate deep link for the cell selection in the notebook document. + return { type: LinkType.Notebook, uri: vscode.window.activeNotebookEditor.notebook.uri, cellIndex: vscode.window.activeNotebookEditor.selection.start, range: undefined }; + } + + return undefined; } function rangeString(range: vscode.Range | undefined) { @@ -43,9 +79,30 @@ function rangeString(range: vscode.Range | undefined) { return hash; } -export function getPermalink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: string): string | undefined { +export function notebookCellRangeString(index: number | undefined, range: vscode.Range | undefined) { + if (index === undefined) { + return ''; + } + + if (!range) { + return `#C${index + 1}`; + } + + let hash = `#C${index + 1}:L${range.start.line + 1}`; + if (range.start.line !== range.end.line) { + hash += `-L${range.end.line + 1}`; + } + return hash; +} + +export function getLink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: string, linkType: 'permalink' | 'headlink' = 'permalink'): string | undefined { hostPrefix = hostPrefix ?? 'https://github.com'; - const { uri, range } = getFileAndPosition(); + const fileAndPosition = getFileAndPosition(); + if (!fileAndPosition) { + return; + } + const uri = fileAndPosition.uri; + // Use the first repo if we cannot determine a repo from the uri. const gitRepo = (uri ? getRepositoryForFile(gitAPI, uri) : gitAPI.repositories[0]) ?? gitAPI.repositories[0]; if (!gitRepo) { @@ -68,9 +125,11 @@ export function getPermalink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: return; } - const commitHash = gitRepo.state.HEAD?.commit; - const fileSegments = (useSelection && uri) ? `${uri.path.substring(gitRepo.rootUri.path.length)}${rangeString(range)}` : ''; + const blobSegment = (gitRepo.state.HEAD?.ahead === 0) ? `/blob/${linkType === 'headlink' ? gitRepo.state.HEAD.name : gitRepo.state.HEAD?.commit}` : ''; + const fileSegments = fileAndPosition.type === LinkType.File + ? (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${rangeString(fileAndPosition.range)}` : '') + : (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${notebookCellRangeString(fileAndPosition.cellIndex, fileAndPosition.range)}` : ''); - return `${hostPrefix}/${repo.owner}/${repo.repo}/blob/${commitHash + return `${hostPrefix}/${repo.owner}/${repo.repo}${blobSegment }${fileSegments}`; } diff --git a/extensions/github/src/publish.ts b/extensions/github/src/publish.ts index fe8a31bbc67..6580e3f78ff 100644 --- a/extensions/github/src/publish.ts +++ b/extensions/github/src/publish.ts @@ -10,6 +10,7 @@ import { getOctokit } from './auth'; import { TextEncoder } from 'util'; import { basename } from 'path'; import { Octokit } from '@octokit/rest'; +import { isInCodespaces } from './pushErrorHandler'; const localize = nls.loadMessageBundle(); @@ -175,32 +176,40 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository) increment: 25 }); - const res = await octokit.repos.createForAuthenticatedUser({ - name: repo!, - private: isPrivate - }); + type CreateRepositoryResponseData = Awaited>['data']; + let createdGithubRepository: CreateRepositoryResponseData | undefined = undefined; - const createdGithubRepository = res.data; - - progress.report({ message: localize('publishing_firstcommit', "Creating first commit"), increment: 25 }); - - if (!repository) { - repository = await gitAPI.init(folder) || undefined; - - if (!repository) { - return; - } - - await repository.commit('first commit', { all: true }); + if (isInCodespaces()) { + createdGithubRepository = await vscode.commands.executeCommand('github.codespaces.publish', { name: repo!, isPrivate }); + } else { + const res = await octokit.repos.createForAuthenticatedUser({ + name: repo!, + private: isPrivate + }); + createdGithubRepository = res.data; } - progress.report({ message: localize('publishing_uploading', "Uploading files"), increment: 25 }); + if (createdGithubRepository) { + progress.report({ message: localize('publishing_firstcommit', "Creating first commit"), increment: 25 }); - const branch = await repository.getBranch('HEAD'); - const protocol = vscode.workspace.getConfiguration('github').get<'https' | 'ssh'>('gitProtocol'); - const remoteUrl = protocol === 'https' ? createdGithubRepository.clone_url : createdGithubRepository.ssh_url; - await repository.addRemote('origin', remoteUrl); - await repository.push('origin', branch.name, true); + if (!repository) { + repository = await gitAPI.init(folder) || undefined; + + if (!repository) { + return; + } + + await repository.commit('first commit', { all: true }); + } + + progress.report({ message: localize('publishing_uploading', "Uploading files"), increment: 25 }); + + const branch = await repository.getBranch('HEAD'); + const protocol = vscode.workspace.getConfiguration('github').get<'https' | 'ssh'>('gitProtocol'); + const remoteUrl = protocol === 'https' ? createdGithubRepository.clone_url : createdGithubRepository.ssh_url; + await repository.addRemote('origin', remoteUrl); + await repository.push('origin', branch.name, true); + } return createdGithubRepository; }); diff --git a/extensions/github/yarn.lock b/extensions/github/yarn.lock index 9933736b08e..c199d2f7553 100644 --- a/extensions/github/yarn.lock +++ b/extensions/github/yarn.lock @@ -2,129 +2,128 @@ # yarn lockfile v1 -"@octokit/auth-token@^2.4.0": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.2.tgz#10d0ae979b100fa6b72fa0e8e63e27e6d0dbff8a" - integrity sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ== +"@octokit/auth-token@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.1.tgz#88bc2baf5d706cb258474e722a720a8365dff2ec" + integrity sha512-/USkK4cioY209wXRpund6HZzHo9GmjakpV9ycOkpMcMxMk7QVcVFVyCMtzvXYiHsB2crgDgrtNYSELYFBXhhaA== dependencies: - "@octokit/types" "^5.0.0" + "@octokit/types" "^7.0.0" -"@octokit/core@^3.0.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.1.1.tgz#1856745aa8fb154cf1544a2a1b82586c809c5e66" - integrity sha512-cQ2HGrtyNJ1IBxpTP1U5m/FkMAJvgw7d2j1q3c9P0XUuYilEgF6e4naTpsgm4iVcQeOnccZlw7XHRIUBy0ymcg== +"@octokit/core@^4.0.0": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.0.5.tgz#589e68c0a35d2afdcd41dafceab072c2fbc6ab5f" + integrity sha512-4R3HeHTYVHCfzSAi0C6pbGXV8UDI5Rk+k3G7kLVNckswN9mvpOzW9oENfjfH3nEmzg8y3AmKmzs8Sg6pLCeOCA== dependencies: - "@octokit/auth-token" "^2.4.0" - "@octokit/graphql" "^4.3.1" - "@octokit/request" "^5.4.0" - "@octokit/types" "^5.0.0" - before-after-hook "^2.1.0" + "@octokit/auth-token" "^3.0.0" + "@octokit/graphql" "^5.0.0" + "@octokit/request" "^6.0.0" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^7.0.0" + before-after-hook "^2.2.0" universal-user-agent "^6.0.0" -"@octokit/endpoint@^6.0.1": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.4.tgz#da3eafdee1fabd6e5b6ca311efcba26f0dd99848" - integrity sha512-ZJHIsvsClEE+6LaZXskDvWIqD3Ao7+2gc66pRG5Ov4MQtMvCU9wGu1TItw9aGNmRuU9x3Fei1yb+uqGaQnm0nw== +"@octokit/endpoint@^7.0.0": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.1.tgz#cb0d03e62e8762f3c80e52b025179de81899a823" + integrity sha512-/wTXAJwt0HzJ2IeE4kQXO+mBScfzyCkI0hMtkIaqyXd9zg76OpOfNQfHL9FlaxAV2RsNiOXZibVWloy8EexENg== dependencies: - "@octokit/types" "^5.0.0" - is-plain-object "^3.0.0" + "@octokit/types" "^7.0.0" + is-plain-object "^5.0.0" universal-user-agent "^6.0.0" -"@octokit/graphql@^4.3.1": - version "4.5.2" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.5.2.tgz#33021ebf94939cf47562823851ab11fe64392274" - integrity sha512-SpB/JGdB7bxRj8qowwfAXjMpICUYSJqRDj26MKJAryRQBqp/ZzARsaO2LEFWzDaps0FLQoPYVGppS0HQXkBhdg== +"@octokit/graphql@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.1.tgz#a06982514ad131fb6fbb9da968653b2233fade9b" + integrity sha512-sxmnewSwAixkP1TrLdE6yRG53eEhHhDTYUykUwdV9x8f91WcbhunIHk9x1PZLALdBZKRPUO2HRcm4kezZ79HoA== dependencies: - "@octokit/request" "^5.3.0" - "@octokit/types" "^5.0.0" + "@octokit/request" "^6.0.0" + "@octokit/types" "^7.0.0" universal-user-agent "^6.0.0" -"@octokit/plugin-paginate-rest@^2.2.0": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.2.3.tgz#a6ad4377e7e7832fb4bdd9d421e600cb7640ac27" - integrity sha512-eKTs91wXnJH8Yicwa30jz6DF50kAh7vkcqCQ9D7/tvBAP5KKkg6I2nNof8Mp/65G0Arjsb4QcOJcIEQY+rK1Rg== - dependencies: - "@octokit/types" "^5.0.0" +"@octokit/openapi-types@^13.6.0": + version "13.6.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-13.6.0.tgz#381884008e23fd82fd444553f6b4dcd24a5c4a4d" + integrity sha512-bxftLwoZ2J6zsU1rzRvk0O32j7lVB0NWWn+P5CDHn9zPzytasR3hdAeXlTngRDkqv1LyEeuy5psVnDkmOSwrcQ== -"@octokit/plugin-request-log@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e" - integrity sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw== - -"@octokit/plugin-rest-endpoint-methods@4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.1.0.tgz#338c568177c4d4d753f9525af88b29cd0f091734" - integrity sha512-zbRTjm+xplSNlixotTVMvLJe8aRogUXS+r37wZK5EjLsNYH4j02K5XLMOWyYaSS4AJEZtPmzCcOcui4VzVGq+A== +"@octokit/plugin-paginate-rest@^4.0.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-4.2.0.tgz#41fc6ca312446a85a4275aca698b4d9c4c5e06ab" + integrity sha512-8otLCIK9esfmOCY14CBnG/xPqv0paf14rc+s9tHpbOpeFwrv5CnECKW1qdqMAT60ngAa9eB1bKQ+l2YCpi0HPQ== dependencies: - "@octokit/types" "^5.1.0" + "@octokit/types" "^7.2.0" + +"@octokit/plugin-request-log@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" + integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== + +"@octokit/plugin-rest-endpoint-methods@^6.0.0": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.4.0.tgz#09584dd4e85fc4fe04ade45620b105af582c20ba" + integrity sha512-YP4eUqZ6vORy/eZOTdil1ZSrMt0kv7i/CVw+HhC2C0yJN+IqTc/rot957JQ7JfyeJD6HZOjLg6Jp1o9cPhI9KA== + dependencies: + "@octokit/types" "^7.2.0" deprecation "^2.3.1" -"@octokit/request-error@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.2.tgz#0e76b83f5d8fdda1db99027ea5f617c2e6ba9ed0" - integrity sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw== +"@octokit/request-error@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.1.tgz#3fd747913c06ab2195e52004a521889dadb4b295" + integrity sha512-ym4Bp0HTP7F3VFssV88WD1ZyCIRoE8H35pXSKwLeMizcdZAYc/t6N9X9Yr9n6t3aG9IH75XDnZ6UeZph0vHMWQ== dependencies: - "@octokit/types" "^5.0.1" + "@octokit/types" "^7.0.0" deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@^5.3.0", "@octokit/request@^5.4.0": - version "5.4.6" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.6.tgz#e8cc8d4cfc654d30428ea92aaa62168fd5ead7eb" - integrity sha512-9r8Sn4CvqFI9LDLHl9P17EZHwj3ehwQnTpTE+LEneb0VBBqSiI/VS4rWIBfBhDrDs/aIGEGZRSB0QWAck8u+2g== +"@octokit/request@^6.0.0": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.1.tgz#3ceeb22dab09a29595d96594b6720fc14495cf4e" + integrity sha512-gYKRCia3cpajRzDSU+3pt1q2OcuC6PK8PmFIyxZDWCzRXRSIBH8jXjFJ8ZceoygBIm0KsEUg4x1+XcYBz7dHPQ== dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.0.0" - "@octokit/types" "^5.0.0" - deprecation "^2.0.0" - is-plain-object "^3.0.0" - node-fetch "^2.3.0" - once "^1.4.0" + "@octokit/endpoint" "^7.0.0" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^7.0.0" + is-plain-object "^5.0.0" + node-fetch "^2.6.7" universal-user-agent "^6.0.0" -"@octokit/rest@^18.0.1": - version "18.0.1" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.0.1.tgz#46ee234770c5ff4c646f7e18708c56b6d7fa3c66" - integrity sha512-KLlJpgsJx88OZ0VLBH3gvUK4sfcXjr/nE0Qzyoe76dNqMzDzkSmmvILF3f2XviGgrzuP6Ie0ay/QX478Vrpn9A== +"@octokit/rest@19.0.4": + version "19.0.4" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.4.tgz#fd8bed1cefffa486e9ae46a9dc608ce81bcfcbdd" + integrity sha512-LwG668+6lE8zlSYOfwPj4FxWdv/qFXYBpv79TWIQEpBLKA9D/IMcWsF/U9RGpA3YqMVDiTxpgVpEW3zTFfPFTA== dependencies: - "@octokit/core" "^3.0.0" - "@octokit/plugin-paginate-rest" "^2.2.0" - "@octokit/plugin-request-log" "^1.0.0" - "@octokit/plugin-rest-endpoint-methods" "4.1.0" + "@octokit/core" "^4.0.0" + "@octokit/plugin-paginate-rest" "^4.0.0" + "@octokit/plugin-request-log" "^1.0.4" + "@octokit/plugin-rest-endpoint-methods" "^6.0.0" -"@octokit/types@^5.0.0", "@octokit/types@^5.0.1", "@octokit/types@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-5.1.0.tgz#4377a3f39edad3e60753fb5c3c310756f1ded57f" - integrity sha512-OFxUBgrEllAbdEmWp/wNmKIu5EuumKHG4sgy56vjZ8lXPgMhF05c76hmulfOdFHHYRpPj49ygOZJ8wgVsPecuA== +"@octokit/types@^7.0.0", "@octokit/types@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-7.2.0.tgz#7ee0fc27f9f463d7ccf12ca5956988d498b3c6c4" + integrity sha512-pYQ/a1U6mHptwhGyp6SvsiM4bWP2s3V95olUeTxas85D/2kN78yN5C8cGN+P4LwJSWUqIEyvq0Qn2WUn6NQRjw== dependencies: - "@types/node" ">= 8" + "@octokit/openapi-types" "^13.6.0" "@types/node@16.x": version "16.11.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -"@types/node@>= 8": - version "14.0.23" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.23.tgz#676fa0883450ed9da0bb24156213636290892806" - integrity sha512-Z4U8yDAl5TFkmYsZdFPdjeMa57NOvnaf1tljHzhouaPEp7LCj2JKkejpI1ODviIAQuW4CcQmxkQ77rnLsOOoKw== - -before-after-hook@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" - integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== +before-after-hook@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" + integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== -is-plain-object@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b" - integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g== +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== -node-fetch@^2.3.0: +node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -153,10 +152,10 @@ universal-user-agent@^6.0.0: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== -vscode-nls@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167" - integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== webidl-conversions@^3.0.0: version "3.0.1" diff --git a/extensions/grunt/package.json b/extensions/grunt/package.json index 8dd9eced530..245fd717f8c 100644 --- a/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:grunt" }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/grunt/yarn.lock b/extensions/grunt/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/grunt/yarn.lock +++ b/extensions/grunt/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -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@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/gulp/package.json b/extensions/gulp/package.json index 8352957083e..062dc4a788f 100644 --- a/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:gulp" }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/gulp/yarn.lock b/extensions/gulp/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/gulp/yarn.lock +++ b/extensions/gulp/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -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@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/handlebars/package.json b/extensions/handlebars/package.json index 0eb6cb2eb2b..88976cf36ff 100644 --- a/extensions/handlebars/package.json +++ b/extensions/handlebars/package.json @@ -36,6 +36,12 @@ "scopeName": "text.html.handlebars", "path": "./syntaxes/Handlebars.tmLanguage.json" } + ], + "htmlLanguageParticipants": [ + { + "languageId": "handlebars", + "autoInsert": true + } ] }, "repository": { diff --git a/extensions/html-language-features/client/src/autoInsertion.ts b/extensions/html-language-features/client/src/autoInsertion.ts index 170afa46c02..e95e6a64a09 100644 --- a/extensions/html-language-features/client/src/autoInsertion.ts +++ b/extensions/html-language-features/client/src/autoInsertion.ts @@ -5,8 +5,9 @@ import { window, workspace, Disposable, TextDocument, Position, SnippetString, TextDocumentChangeEvent, TextDocumentChangeReason, TextDocumentContentChangeEvent } from 'vscode'; import { Runtime } from './htmlClient'; +import { LanguageParticipants } from './languageParticipants'; -export function activateAutoInsertion(provider: (kind: 'autoQuote' | 'autoClose', document: TextDocument, position: Position) => Thenable, supportedLanguages: { [id: string]: boolean }, runtime: Runtime): Disposable { +export function activateAutoInsertion(provider: (kind: 'autoQuote' | 'autoClose', document: TextDocument, position: Position) => Thenable, languageParticipants: LanguageParticipants, runtime: Runtime): Disposable { const disposables: Disposable[] = []; workspace.onDidChangeTextDocument(onDidChangeTextDocument, null, disposables); @@ -33,7 +34,7 @@ export function activateAutoInsertion(provider: (kind: 'autoQuote' | 'autoClose' return; } const document = editor.document; - if (!supportedLanguages[document.languageId]) { + if (!languageParticipants.useAutoInsert(document.languageId)) { return; } const configurations = workspace.getConfiguration(undefined, document.uri); diff --git a/extensions/html-language-features/client/src/browser/htmlClientMain.ts b/extensions/html-language-features/client/src/browser/htmlClientMain.ts index ab23520fe79..fb8cc9071a8 100644 --- a/extensions/html-language-features/client/src/browser/htmlClientMain.ts +++ b/extensions/html-language-features/client/src/browser/htmlClientMain.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, ExtensionContext, Uri } from 'vscode'; -import { BaseLanguageClient, LanguageClientOptions } from 'vscode-languageclient'; -import { startClient, LanguageClientConstructor } from '../htmlClient'; +import { LanguageClientOptions } from 'vscode-languageclient'; +import { startClient, LanguageClientConstructor, AsyncDisposable } from '../htmlClient'; import { LanguageClient } from 'vscode-languageclient/browser'; declare const Worker: { @@ -15,7 +15,7 @@ declare const TextDecoder: { new(encoding?: string): { decode(buffer: ArrayBuffer): string }; }; -let client: BaseLanguageClient | undefined; +let client: AsyncDisposable | undefined; // this method is called when vs code is activated export async function activate(context: ExtensionContext) { @@ -42,7 +42,7 @@ export async function activate(context: ExtensionContext) { export async function deactivate(): Promise { if (client) { - await client.stop(); + await client.dispose(); client = undefined; } } diff --git a/extensions/html-language-features/client/src/customData.ts b/extensions/html-language-features/client/src/customData.ts index 80e5f2f04d9..71d847a4f39 100644 --- a/extensions/html-language-features/client/src/customData.ts +++ b/extensions/html-language-features/client/src/customData.ts @@ -125,7 +125,7 @@ function collectInWorkspaces(workspaceUris: Set): Set { } function collectInExtensions(localExtensionUris: Set, externalUris: Set): void { - for (const extension of extensions.all) { + for (const extension of extensions.allAcrossExtensionHosts) { const customData = extension.packageJSON?.contributes?.html?.customData; if (Array.isArray(customData)) { for (const uriOrPath of customData) { diff --git a/extensions/html-language-features/client/src/htmlClient.ts b/extensions/html-language-features/client/src/htmlClient.ts index 60accb3870b..d5cf527713f 100644 --- a/extensions/html-language-features/client/src/htmlClient.ts +++ b/extensions/html-language-features/client/src/htmlClient.ts @@ -9,7 +9,7 @@ const localize = nls.loadMessageBundle(); import { languages, ExtensionContext, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace, extensions, Disposable, FormattingOptions, CancellationToken, ProviderResult, TextEdit, CompletionContext, CompletionList, SemanticTokensLegend, - DocumentSemanticTokensProvider, DocumentRangeSemanticTokensProvider, SemanticTokens, window, commands + DocumentSemanticTokensProvider, DocumentRangeSemanticTokensProvider, SemanticTokens, window, commands, OutputChannel } from 'vscode'; import { LanguageClientOptions, RequestType, DocumentRangeFormattingParams, @@ -18,6 +18,7 @@ import { import { FileSystemProvider, serveFileSystemRequests } from './requests'; import { getCustomDataSource } from './customData'; import { activateAutoInsertion } from './autoInsertion'; +import { getLanguageParticipants, LanguageParticipants } from './languageParticipants'; namespace CustomDataChangedNotification { export const type: NotificationType = new NotificationType('html/customDataChanged'); @@ -74,6 +75,8 @@ export interface TelemetryReporter { export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient; +export const languageServerDescription = localize('htmlserver.name', 'HTML Language Server'); + export interface Runtime { TextDecoder: { new(encoding?: string): { decode(buffer: ArrayBuffer): string } }; fileFs?: FileSystemProvider; @@ -83,11 +86,69 @@ export interface Runtime { }; } -export async function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime): Promise { +export interface AsyncDisposable { + dispose(): Promise; +} - const toDispose = context.subscriptions; +export async function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime): Promise { - const documentSelector = ['html', 'handlebars']; + const outputChannel = window.createOutputChannel(languageServerDescription); + + const languageParticipants = getLanguageParticipants(); + context.subscriptions.push(languageParticipants); + + let client: Disposable | undefined = await startClientWithParticipants(languageParticipants, newLanguageClient, outputChannel, runtime); + + const promptForLinkedEditingKey = 'html.promptForLinkedEditing'; + if (extensions.getExtension('formulahendry.auto-rename-tag') !== undefined && (context.globalState.get(promptForLinkedEditingKey) !== false)) { + const config = workspace.getConfiguration('editor', { languageId: 'html' }); + if (!config.get('linkedEditing') && !config.get('renameOnType')) { + const activeEditorListener = window.onDidChangeActiveTextEditor(async e => { + if (e && languageParticipants.hasLanguage(e.document.languageId)) { + context.globalState.update(promptForLinkedEditingKey, false); + activeEditorListener.dispose(); + const configure = localize('configureButton', 'Configure'); + const res = await window.showInformationMessage(localize('linkedEditingQuestion', 'VS Code now has built-in support for auto-renaming tags. Do you want to enable it?'), configure); + if (res === configure) { + commands.executeCommand('workbench.action.openSettings', SettingIds.linkedEditing); + } + } + }); + context.subscriptions.push(activeEditorListener); + } + } + + let restartTrigger: Disposable | undefined; + languageParticipants.onDidChange(() => { + if (restartTrigger) { + restartTrigger.dispose(); + } + restartTrigger = runtime.timer.setTimeout(async () => { + if (client) { + outputChannel.appendLine('Extensions have changed, restarting HTML server...'); + outputChannel.appendLine(''); + const oldClient = client; + client = undefined; + await oldClient.dispose(); + client = await startClientWithParticipants(languageParticipants, newLanguageClient, outputChannel, runtime); + } + }, 2000); + }); + + return { + dispose: async () => { + restartTrigger?.dispose(); + await client?.dispose(); + outputChannel.dispose(); + } + }; +} + +async function startClientWithParticipants(languageParticipants: LanguageParticipants, newLanguageClient: LanguageClientConstructor, outputChannel: OutputChannel, runtime: Runtime): Promise { + + const toDispose: Disposable[] = []; + + const documentSelector = languageParticipants.documentSelector; const embeddedLanguages = { css: true, javascript: true }; let rangeFormatting: Disposable | undefined = undefined; @@ -129,22 +190,23 @@ export async function startClient(context: ExtensionContext, newLanguageClient: } } }; + clientOptions.outputChannel = outputChannel; // Create the language client and start the client. - const client = newLanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), clientOptions); + const client = newLanguageClient('html', languageServerDescription, clientOptions); client.registerProposedFeatures(); await client.start(); toDispose.push(serveFileSystemRequests(client, runtime)); - const customDataSource = getCustomDataSource(runtime, context.subscriptions); + const customDataSource = getCustomDataSource(runtime, toDispose); client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris); customDataSource.onDidChange(() => { client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris); - }); - client.onRequest(CustomDataContent.type, customDataSource.getContent); + }, undefined, toDispose); + toDispose.push(client.onRequest(CustomDataContent.type, customDataSource.getContent)); const insertRequestor = (kind: 'autoQuote' | 'autoClose', document: TextDocument, position: Position): Promise => { @@ -155,7 +217,8 @@ export async function startClient(context: ExtensionContext, newLanguageClient: }; return client.sendRequest(AutoInsertRequest.type, param); }; - const disposable = activateAutoInsertion(insertRequestor, { html: true, handlebars: true }, runtime); + + const disposable = activateAutoInsertion(insertRequestor, languageParticipants, runtime); toDispose.push(disposable); const disposable2 = client.onTelemetry(e => { @@ -193,7 +256,6 @@ export async function startClient(context: ExtensionContext, newLanguageClient: } }); - function updateFormatterRegistration() { const formatEnabled = workspace.getConfiguration().get(SettingIds.formatEnable); if (!formatEnabled && rangeFormatting) { @@ -278,25 +340,12 @@ export async function startClient(context: ExtensionContext, newLanguageClient: } })); - const promptForLinkedEditingKey = 'html.promptForLinkedEditing'; - if (extensions.getExtension('formulahendry.auto-rename-tag') !== undefined && (context.globalState.get(promptForLinkedEditingKey) !== false)) { - const config = workspace.getConfiguration('editor', { languageId: 'html' }); - if (!config.get('linkedEditing') && !config.get('renameOnType')) { - const activeEditorListener = window.onDidChangeActiveTextEditor(async e => { - if (e && documentSelector.indexOf(e.document.languageId) !== -1) { - context.globalState.update(promptForLinkedEditingKey, false); - activeEditorListener.dispose(); - const configure = localize('configureButton', 'Configure'); - const res = await window.showInformationMessage(localize('linkedEditingQuestion', 'VS Code now has built-in support for auto-renaming tags. Do you want to enable it?'), configure); - if (res === configure) { - commands.executeCommand('workbench.action.openSettings', SettingIds.linkedEditing); - } - } - }); - toDispose.push(activeEditorListener); + return { + dispose: async () => { + await client.stop(); + toDispose.forEach(d => d.dispose()); + rangeFormatting?.dispose(); } - } - - return client; + }; } diff --git a/extensions/html-language-features/client/src/languageParticipants.ts b/extensions/html-language-features/client/src/languageParticipants.ts new file mode 100644 index 00000000000..6abe49237c8 --- /dev/null +++ b/extensions/html-language-features/client/src/languageParticipants.ts @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DocumentSelector } from 'vscode-languageclient'; +import { Event, EventEmitter, extensions } from 'vscode'; + +/** + * HTML language participant contribution. + */ +interface LanguageParticipantContribution { + /** + * The id of the language which participates with the HTML language server. + */ + languageId: string; + /** + * true if the language activates the auto insertion and false otherwise. + */ + autoInsert?: boolean; +} + +export interface LanguageParticipants { + readonly onDidChange: Event; + readonly documentSelector: DocumentSelector; + hasLanguage(languageId: string): boolean; + useAutoInsert(languageId: string): boolean; + dispose(): void; +} + +export function getLanguageParticipants(): LanguageParticipants { + const onDidChangeEmmiter = new EventEmitter(); + let languages = new Set(); + let autoInsert = new Set(); + + function update() { + const oldLanguages = languages, oldAutoInsert = autoInsert; + + languages = new Set(); + languages.add('html'); + autoInsert = new Set(); + autoInsert.add('html'); + + for (const extension of extensions.allAcrossExtensionHosts) { + const htmlLanguageParticipants = extension.packageJSON?.contributes?.htmlLanguageParticipants as LanguageParticipantContribution[]; + if (Array.isArray(htmlLanguageParticipants)) { + for (const htmlLanguageParticipant of htmlLanguageParticipants) { + const languageId = htmlLanguageParticipant.languageId; + if (typeof languageId === 'string') { + languages.add(languageId); + if (htmlLanguageParticipant.autoInsert !== false) { + autoInsert.add(languageId); + } + } + } + } + } + return !isEqualSet(languages, oldLanguages) || !isEqualSet(oldLanguages, oldAutoInsert); + } + update(); + + const changeListener = extensions.onDidChange(_ => { + if (update()) { + onDidChangeEmmiter.fire(); + } + }); + + return { + onDidChange: onDidChangeEmmiter.event, + get documentSelector() { return Array.from(languages); }, + hasLanguage(languageId: string) { return languages.has(languageId); }, + useAutoInsert(languageId: string) { return autoInsert.has(languageId); }, + dispose: () => changeListener.dispose() + }; +} + +function isEqualSet(s1: Set, s2: Set) { + if (s1.size !== s2.size) { + return false; + } + for (const e of s1) { + if (!s2.has(e)) { + return false; + } + } + return true; +} diff --git a/extensions/html-language-features/client/src/node/htmlClientMain.ts b/extensions/html-language-features/client/src/node/htmlClientMain.ts index 11ca6f254f9..c3e8c85cf4f 100644 --- a/extensions/html-language-features/client/src/node/htmlClientMain.ts +++ b/extensions/html-language-features/client/src/node/htmlClientMain.ts @@ -5,15 +5,15 @@ import { getNodeFileFS } from './nodeFs'; import { Disposable, ExtensionContext } from 'vscode'; -import { startClient, LanguageClientConstructor } from '../htmlClient'; -import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient, BaseLanguageClient } from 'vscode-languageclient/node'; +import { startClient, LanguageClientConstructor, AsyncDisposable } from '../htmlClient'; +import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient } from 'vscode-languageclient/node'; import { TextDecoder } from 'util'; import * as fs from 'fs'; import TelemetryReporter from '@vscode/extension-telemetry'; let telemetry: TelemetryReporter | undefined; -let client: BaseLanguageClient | undefined; +let client: AsyncDisposable | undefined; // this method is called when vs code is activated export async function activate(context: ExtensionContext) { @@ -50,7 +50,7 @@ export async function activate(context: ExtensionContext) { export async function deactivate(): Promise { if (client) { - await client.stop(); + await client.dispose(); client = undefined; } } diff --git a/extensions/html-language-features/client/tsconfig.json b/extensions/html-language-features/client/tsconfig.json index 573b24b4aa6..8f5cef74fd3 100644 --- a/extensions/html-language-features/client/tsconfig.json +++ b/extensions/html-language-features/client/tsconfig.json @@ -5,6 +5,7 @@ }, "include": [ "src/**/*", - "../../../src/vscode-dts/vscode.d.ts" + "../../../src/vscode-dts/vscode.d.ts", + "../../../src/vscode-dts/vscode.proposed.extensionsAny.d.ts" ] } diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index 51d53e8984a..1c4d2b83041 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -5,7 +5,7 @@ "version": "1.0.0", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "0.10.x" }, @@ -14,6 +14,9 @@ "onLanguage:html", "onLanguage:handlebars" ], + "enabledApiProposals": [ + "extensionsAny" + ], "main": "./client/out/node/htmlClientMain", "browser": "./client/dist/browser/htmlClientMain", "capabilities": { @@ -255,9 +258,9 @@ ] }, "dependencies": { - "@vscode/extension-telemetry": "0.5.1", - "vscode-languageclient": "^8.0.2-next.4", - "vscode-nls": "^5.0.1", + "@vscode/extension-telemetry": "0.6.2", + "vscode-languageclient": "^8.1.0-next.1", + "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/html-language-features/schemas/package.schema.json b/extensions/html-language-features/schemas/package.schema.json index a4d8715b918..ef717dbd1d1 100644 --- a/extensions/html-language-features/schemas/package.schema.json +++ b/extensions/html-language-features/schemas/package.schema.json @@ -13,6 +13,23 @@ "type": "string", "description": "Relative path to a HTML custom data file" } + }, + "htmlLanguageParticipants": { + "type": "array", + "description": "A list of languages that participate with the HTML language server.", + "items": { + "type": "object", + "properties": { + "languageId": { + "type": "string", + "description": "The id of the language that participates with HTML language server." + }, + "autoInsert": { + "type": "boolean", + "description": "Whether the language participates with HTML auto insertions. If not specified, defaults to true." + } + } + } } } } diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index 322f6b81f85..fc15c48b76b 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,11 +9,11 @@ }, "main": "./out/node/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^6.0.1", - "vscode-html-languageservice": "^5.0.0", - "vscode-languageserver": "^8.0.2-next.4", - "vscode-languageserver-textdocument": "^1.0.4", - "vscode-nls": "^5.0.1", + "vscode-css-languageservice": "^6.1.0", + "vscode-html-languageservice": "^5.0.1", + "vscode-languageserver": "^8.1.0-next.1", + "vscode-languageserver-textdocument": "^1.0.7", + "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/html-language-features/server/src/modes/javascriptMode.ts b/extensions/html-language-features/server/src/modes/javascriptMode.ts index 10a70dbe99a..0c199571dd7 100644 --- a/extensions/html-language-features/server/src/modes/javascriptMode.ts +++ b/extensions/html-language-features/server/src/modes/javascriptMode.ts @@ -93,13 +93,16 @@ function getLanguageServiceHost(scriptKind: ts.ScriptKind) { }; } +const ignoredErrors = [ + 1108, /* A_return_statement_can_only_be_used_within_a_function_body_1108 */ + 2792, /* Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option */ +]; export function getJavaScriptMode(documentRegions: LanguageModelCache, languageId: 'javascript' | 'typescript', workspace: Workspace): LanguageMode { const jsDocuments = getLanguageModelCache(10, 60, document => documentRegions.get(document).getEmbeddedDocument(languageId)); const host = getLanguageServiceHost(languageId === 'javascript' ? ts.ScriptKind.JS : ts.ScriptKind.TS); const globalSettings: Settings = {}; - return { getId() { return languageId; @@ -110,7 +113,7 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache d.code !== 1108).map((diag: ts.Diagnostic): Diagnostic => { + return syntaxDiagnostics.concat(semanticDiagnostics).filter(d => !ignoredErrors.includes(d.code)).map((diag: ts.Diagnostic): Diagnostic => { return { range: convertRange(jsDocument, diag), severity: DiagnosticSeverity.Error, diff --git a/extensions/html-language-features/server/src/utils/documentContext.ts b/extensions/html-language-features/server/src/utils/documentContext.ts index fb1a6622674..88e3f032885 100644 --- a/extensions/html-language-features/server/src/utils/documentContext.ts +++ b/extensions/html-language-features/server/src/utils/documentContext.ts @@ -24,6 +24,10 @@ export function getDocumentContext(documentUri: string, workspaceFolders: Worksp return { resolveReference: (ref: string, base = documentUri) => { + if (ref.match(/^\w[\w\d+.-]*:/)) { + // starts with a schema + return ref; + } if (ref[0] === '/') { // resolve absolute path against the current workspace folder const folderUri = getRootFolder(); if (folderUri) { diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 6f3a8b7b5b1..d561fbe7678 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -12,66 +12,76 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-css-languageservice@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.0.1.tgz#ccf94944e094dcc5833d1b4ac276994b698e9283" - integrity sha512-81n/eeYuJwQdvpoy6IK1258PtPbO720fl13FcJ5YQECPyHMFkmld1qKHwPJkyLbLPfboqJPM53ys4xW8v+iBVw== +vscode-css-languageservice@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.1.0.tgz#fa5408307de1bee817b65efaff284da8a2eca987" + integrity sha512-GFXmy6EVceVc/OPKENnoW31EiIksekz9yruczIAkA0eX5BSkNh/ojgeCzwW1ERRFpDymVZj0aLYKSrYZmvU6VA== + dependencies: + vscode-languageserver-textdocument "^1.0.7" + vscode-languageserver-types "^3.17.2" + vscode-nls "^5.2.0" + vscode-uri "^3.0.3" + +vscode-html-languageservice@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-5.0.1.tgz#bdf7847d27a453a9e98ae2836ead7594784c5c1c" + integrity sha512-OYsyn5HGAhxs0OIG+M0jc34WnftLtD67Wg7+TfrYwvf0waOkkr13zUqtdrVm2JPNQ6fJx+qnuM+vTbq7o1dCdQ== dependencies: vscode-languageserver-textdocument "^1.0.4" vscode-languageserver-types "^3.17.1" vscode-nls "^5.0.1" vscode-uri "^3.0.3" -vscode-html-languageservice@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-5.0.0.tgz#c68613f836d7fcff125183d78e6f1f0ff326fa55" - integrity sha512-KJG13z54aLszskp3ETf8b1EKDypr2Sf5RUsfR6OXmKqEl2ZUfyIxsWz4gbJWjPzoJZx/bGH0ZXVwxJ1rg8OKRQ== - dependencies: - vscode-languageserver-textdocument "^1.0.4" - vscode-languageserver-types "^3.17.1" - vscode-nls "^5.0.1" - vscode-uri "^3.0.3" +vscode-jsonrpc@8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0-next.1.tgz#7c38cb1cbd968c409522593004fdac845a55b155" + integrity sha512-FiPG+9TuMIga3t+kkalQytwqMtJu1djI+Pq+Ut2tvAJpcNHDJ0PYdjFv5mgEvTEJLujrYwjWHVkNe+XfHPBD/w== -vscode-jsonrpc@8.0.2-next.1: - version "8.0.2-next.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz#6bdc39fd194782032e34047eeefce562941259c6" - integrity sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA== - -vscode-languageserver-protocol@3.17.2-next.5: - version "3.17.2-next.5" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.5.tgz#9bc747411c3ce9e1d73c2714bf6555e0199eec26" - integrity sha512-UlH+QL4Q4lX94of/UPDDwwWIkd8w7dtMW4khzvEDUoykiG9tba0iG6V0bAiv8XVpnBIUYjL2FNFiL3zl+TY1Sw== +vscode-languageserver-protocol@3.17.3-next.1: + version "3.17.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3-next.1.tgz#804880c172b4c48d1a48a91c4c23250121effb19" + integrity sha512-vgjvPE0zox+1Fi4ljsSFJ+B3g8wGNbuAEEdulueVdv+R2VHtc06+dgxhWiG4LKPqXwjPDmiuxCnvd2xk3fzTTw== dependencies: - vscode-jsonrpc "8.0.2-next.1" - vscode-languageserver-types "3.17.2-next.2" + vscode-jsonrpc "8.1.0-next.1" + vscode-languageserver-types "3.17.2" vscode-languageserver-textdocument@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== -vscode-languageserver-types@3.17.2-next.2: - version "3.17.2-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" - integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== +vscode-languageserver-textdocument@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz#16df468d5c2606103c90554ae05f9f3d335b771b" + integrity sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg== + +vscode-languageserver-types@3.17.2, vscode-languageserver-types@^3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== vscode-languageserver-types@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== -vscode-languageserver@^8.0.2-next.4: - version "8.0.2-next.4" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2-next.4.tgz#c10cc95be06325b56b7ec1d10271c9e4adf3ef07" - integrity sha512-B3roWH4TmJiB6Zh5+r7zu0QdlLqJsPdGo0LeEi6OiLfrHYCDlcI7DNcQ7F17vWmxC3C82SrxMt/EuLBMpKQM0A== +vscode-languageserver@^8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.1.0-next.1.tgz#1c173de554889bd18ca6e20eaf4bdc84164c86b4" + integrity sha512-u14Rk4JgXI+7iS6AEXI2pNc1dWh/5JEXtaqa4TeBECKJlN+5242mbGBBPaHMOE7sSI1Kh66XhEMZJhPYjUfjHw== dependencies: - vscode-languageserver-protocol "3.17.2-next.5" + vscode-languageserver-protocol "3.17.3-next.1" vscode-nls@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== + vscode-uri@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" diff --git a/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock index c7c2faeae0f..eb21b32ad68 100644 --- a/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -2,33 +2,66 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.6", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.6.tgz#8a77909f89f991aa2f0b4ae8825c75042962e68e" + integrity sha512-6OpppYCEA+rXjcs2w0KnWji3Y6ZDx0wykY7ZL3QF68NS323C45GHSpkDpVRT/lDU6Xbau/PvQm2zTYAzLcperA== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.6" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.6.tgz#cdfa74acfc3205c0a5b79925284d6d166aa43901" + integrity sha512-Zdyl3FU6kU/a7TlVVSTBZg+hSECTT65iI99FsjMOx88HudyVyk9M/0lVbA+FVXvGaxzmtBW6Lw0qRHYp4tBMSA== + dependencies: + "@microsoft/1ds-core-js" "3.2.6" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.6": + version "2.8.6" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.6.tgz#4f0f9ad809aacfc96cb882139b69b3625519c51a" + integrity sha512-rL+ceda1Y6HaHBe1vIbNT/f5JGuHiD5Ydq+DoAfu56o13wyJu4sao3QKaabgaIM59pPO+3BMeGsK8NNUGYaT3w== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node@16.x": version "16.11.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -"@vscode/extension-telemetry@0.5.1": - version "0.5.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.5.1.tgz#20150976629663b3d33799a4ad25944a1535f7db" - integrity sha512-cvFq8drxdLRF8KN72WcV4lTEa9GqDiRwy9EbnYuoSCD9Jdk8zHFF49MmACC1qs4R9Ko/C1uMOmeLJmVi8EA0rQ== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" - concat-map "0.0.1" - -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= lru-cache@^6.0.0: version "6.0.0" @@ -37,51 +70,51 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +minimatch@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" + integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" -semver@^7.3.5: +semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -vscode-jsonrpc@8.0.2-next.1: - version "8.0.2-next.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz#6bdc39fd194782032e34047eeefce562941259c6" - integrity sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA== +vscode-jsonrpc@8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0-next.1.tgz#7c38cb1cbd968c409522593004fdac845a55b155" + integrity sha512-FiPG+9TuMIga3t+kkalQytwqMtJu1djI+Pq+Ut2tvAJpcNHDJ0PYdjFv5mgEvTEJLujrYwjWHVkNe+XfHPBD/w== -vscode-languageclient@^8.0.2-next.4: - version "8.0.2-next.4" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.2-next.4.tgz#87dd364ffbd4356aff3af14e7b557d9fe34d2b67" - integrity sha512-j9BEiCYMN9IoKwYdk9iickV6WNPVGPoVO11SMdoxFnWPIT3y5UAe3qf/WsfA9OdklAIaxxYasfgyKCpBjSPNuw== +vscode-languageclient@^8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.1.0-next.1.tgz#44b63bc2d215c13f1dea1dc54267a354ea5451cb" + integrity sha512-lJraJ8IrqXr83ZciAs4dN32f9kEPuOb/FqAeUTgnW5cAxo0Qux0/EMgKyU33Qf9LdEI0I9iwRVxQWtawbyUUfg== dependencies: - minimatch "^3.0.4" - semver "^7.3.5" - vscode-languageserver-protocol "3.17.2-next.5" + minimatch "^5.1.0" + semver "^7.3.7" + vscode-languageserver-protocol "3.17.3-next.1" -vscode-languageserver-protocol@3.17.2-next.5: - version "3.17.2-next.5" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.5.tgz#9bc747411c3ce9e1d73c2714bf6555e0199eec26" - integrity sha512-UlH+QL4Q4lX94of/UPDDwwWIkd8w7dtMW4khzvEDUoykiG9tba0iG6V0bAiv8XVpnBIUYjL2FNFiL3zl+TY1Sw== +vscode-languageserver-protocol@3.17.3-next.1: + version "3.17.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3-next.1.tgz#804880c172b4c48d1a48a91c4c23250121effb19" + integrity sha512-vgjvPE0zox+1Fi4ljsSFJ+B3g8wGNbuAEEdulueVdv+R2VHtc06+dgxhWiG4LKPqXwjPDmiuxCnvd2xk3fzTTw== dependencies: - vscode-jsonrpc "8.0.2-next.1" - vscode-languageserver-types "3.17.2-next.2" + vscode-jsonrpc "8.1.0-next.1" + vscode-languageserver-types "3.17.2" -vscode-languageserver-types@3.17.2-next.2: - version "3.17.2-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" - integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== +vscode-languageserver-types@3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== -vscode-nls@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" - integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/image-preview/media/audioPreview.css b/extensions/image-preview/media/audioPreview.css new file mode 100644 index 00000000000..0f72113bea8 --- /dev/null +++ b/extensions/image-preview/media/audioPreview.css @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +html, body { + width: 100%; + height: 100%; + text-align: center; +} + +body { + padding: 5px 10px; + box-sizing: border-box; + -webkit-user-select: none; + user-select: none; +} + +.audio-container { + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.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, +.loading-error { + display: none; +} + +.loading .loading-indicator, +.error .loading-error { + display: block; +} + +.loading-error { + 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/audioPreview.js b/extensions/image-preview/media/audioPreview.js new file mode 100644 index 00000000000..ea5d6f64ea4 --- /dev/null +++ b/extensions/image-preview/media/audioPreview.js @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// @ts-check +"use strict"; + +(function () { + const vscode = acquireVsCodeApi(); + + function getSettings() { + const element = document.getElementById('settings'); + if (element) { + const data = element.getAttribute('data-settings'); + if (data) { + return JSON.parse(data); + } + } + + throw new Error(`Could not load settings`); + } + + const settings = getSettings(); + + // State + let hasLoadedMedia = false; + + // Elements + const container = document.createElement('div'); + container.className = 'audio-container'; + document.body.appendChild(container); + + const audio = new Audio(settings.src === null ? undefined : settings.src); + audio.controls = true; + + function onLoaded() { + if (hasLoadedMedia) { + return; + } + hasLoadedMedia = true; + + document.body.classList.remove('loading'); + document.body.classList.add('ready'); + container.append(audio); + } + + audio.addEventListener('error', e => { + if (hasLoadedMedia) { + return; + } + + hasLoadedMedia = true; + document.body.classList.add('error'); + document.body.classList.remove('loading'); + }); + + if (settings.src === null) { + onLoaded(); + } else { + audio.addEventListener('canplaythrough', () => { + onLoaded(); + }); + } + + document.querySelector('.open-file-link').addEventListener('click', () => { + vscode.postMessage({ + type: 'reopen-as-text', + }); + }); +}()); diff --git a/extensions/image-preview/media/main.css b/extensions/image-preview/media/imagePreview.css similarity index 100% rename from extensions/image-preview/media/main.css rename to extensions/image-preview/media/imagePreview.css diff --git a/extensions/image-preview/media/main.js b/extensions/image-preview/media/imagePreview.js similarity index 100% rename from extensions/image-preview/media/main.js rename to extensions/image-preview/media/imagePreview.js diff --git a/extensions/image-preview/media/videoPreview.css b/extensions/image-preview/media/videoPreview.css new file mode 100644 index 00000000000..3e98ac9e2f8 --- /dev/null +++ b/extensions/image-preview/media/videoPreview.css @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +html, body { + width: 100%; + height: 100%; + text-align: center; +} + +body { + padding: 5px 10px; + box-sizing: border-box; + -webkit-user-select: none; + user-select: none; +} + +.video-container { + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.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, +.loading-error { + display: none; +} + +.loading .loading-indicator, +.error .loading-error { + display: block; +} + +.loading-error { + 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/videoPreview.js b/extensions/image-preview/media/videoPreview.js new file mode 100644 index 00000000000..1550dba6a63 --- /dev/null +++ b/extensions/image-preview/media/videoPreview.js @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// @ts-check +"use strict"; + +(function () { + const vscode = acquireVsCodeApi(); + + function getSettings() { + const element = document.getElementById('settings'); + if (element) { + const data = element.getAttribute('data-settings'); + if (data) { + return JSON.parse(data); + } + } + + throw new Error(`Could not load settings`); + } + + const settings = getSettings(); + + // State + let hasLoadedMedia = false; + + // Elements + const container = document.createElement('div'); + container.className = 'video-container'; + document.body.appendChild(container); + + const video = document.createElement('video'); + if (settings.src !== null) { + video.src = settings.src; + } + video.controls = true; + + function onLoaded() { + if (hasLoadedMedia) { + return; + } + hasLoadedMedia = true; + + document.body.classList.remove('loading'); + document.body.classList.add('ready'); + container.append(video); + } + + video.addEventListener('error', e => { + if (hasLoadedMedia) { + return; + } + + hasLoadedMedia = true; + document.body.classList.add('error'); + document.body.classList.remove('loading'); + }); + + if (settings.src === null) { + onLoaded(); + } else { + video.addEventListener('canplaythrough', () => { + onLoaded(); + }); + } + + document.querySelector('.open-file-link').addEventListener('click', () => { + vscode.postMessage({ + type: 'reopen-as-text', + }); + }); +}()); diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index b6ff3579894..4b9ca1c1507 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -10,7 +10,7 @@ "publisher": "vscode", "icon": "icon.png", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.39.0" }, @@ -22,7 +22,9 @@ "activationEvents": [ "onCustomEditor:imagePreview.previewEditor", "onCommand:imagePreview.zoomIn", - "onCommand:imagePreview.zoomOut" + "onCommand:imagePreview.zoomOut", + "onCustomEditor:vscode.audioPreview", + "onCustomEditor:vscode.videoPreview" ], "capabilities": { "virtualWorkspaces": true, @@ -34,13 +36,33 @@ "customEditors": [ { "viewType": "imagePreview.previewEditor", - "displayName": "%customEditors.displayName%", + "displayName": "%customEditor.imagePreview.displayName%", "priority": "builtin", "selector": [ { "filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,webp,avif}" } ] + }, + { + "viewType": "vscode.audioPreview", + "displayName": "%customEditor.audioPreview.displayName%", + "priority": "builtin", + "selector": [ + { + "filenamePattern": "*.{mp3,wav,opus,aac}" + } + ] + }, + { + "viewType": "vscode.videoPreview", + "displayName": "%customEditor.videoPreview.displayName%", + "priority": "builtin", + "selector": [ + { + "filenamePattern": "*.{mp4}" + } + ] } ], "commands": [ @@ -79,8 +101,8 @@ "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, "dependencies": { - "@vscode/extension-telemetry": "0.6.1", - "vscode-nls": "^5.0.0" + "@vscode/extension-telemetry": "0.6.2", + "vscode-nls": "^5.1.0" }, "repository": { "type": "git", diff --git a/extensions/image-preview/package.nls.json b/extensions/image-preview/package.nls.json index d1860bc2fb5..423aaf0c82b 100644 --- a/extensions/image-preview/package.nls.json +++ b/extensions/image-preview/package.nls.json @@ -1,7 +1,9 @@ { "displayName": "Image Preview", "description": "Provides VS Code's built-in image preview", - "customEditors.displayName": "Image Preview", + "customEditor.audioPreview.displayName": "Audio Preview", + "customEditor.imagePreview.displayName": "Image Preview", + "customEditor.videoPreview.displayName": "Video Preview", "command.zoomIn": "Zoom in", "command.zoomOut": "Zoom out" } diff --git a/extensions/image-preview/src/audioPreview.ts b/extensions/image-preview/src/audioPreview.ts new file mode 100644 index 00000000000..2769ae3cbfb --- /dev/null +++ b/extensions/image-preview/src/audioPreview.ts @@ -0,0 +1,122 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; +import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry'; +import { MediaPreview, reopenAsText } from './mediaPreview'; +import { escapeAttribute, getNonce } from './util/dom'; + +const localize = nls.loadMessageBundle(); + +class AudioPreviewProvider implements vscode.CustomReadonlyEditorProvider { + + public static readonly viewType = 'vscode.audioPreview'; + + constructor( + private readonly extensionRoot: vscode.Uri, + private readonly binarySizeStatusBarEntry: BinarySizeStatusBarEntry, + ) { } + + public async openCustomDocument(uri: vscode.Uri) { + return { uri, dispose: () => { } }; + } + + public async resolveCustomEditor(document: vscode.CustomDocument, webviewEditor: vscode.WebviewPanel): Promise { + new AudioPreview(this.extensionRoot, document.uri, webviewEditor, this.binarySizeStatusBarEntry); + } +} + + +class AudioPreview extends MediaPreview { + + constructor( + private readonly extensionRoot: vscode.Uri, + resource: vscode.Uri, + webviewEditor: vscode.WebviewPanel, + binarySizeStatusBarEntry: BinarySizeStatusBarEntry, + ) { + super(extensionRoot, resource, webviewEditor, binarySizeStatusBarEntry); + + this._register(webviewEditor.webview.onDidReceiveMessage(message => { + switch (message.type) { + case 'reopen-as-text': { + reopenAsText(resource, webviewEditor.viewColumn); + break; + } + } + })); + + this.updateBinarySize(); + this.render(); + this.updateState(); + } + + protected async getWebviewContents(): Promise { + const version = Date.now().toString(); + const settings = { + src: await this.getResourcePath(this.webviewEditor, this.resource, version), + }; + + const nonce = getNonce(); + + const cspSource = this.webviewEditor.webview.cspSource; + return /* html */` + + + + + + + + Audio Preview + + + + + + + +
+
+

${localize('preview.audioLoadError', "An error occurred while loading the audio file.")}

+ ${localize('preview.audioLoadErrorLink', "Open file using VS Code's standard text/binary editor?")} +
+ + +`; + } + + private async getResourcePath(webviewEditor: vscode.WebviewPanel, resource: vscode.Uri, version: string): Promise { + if (resource.scheme === 'git') { + const stat = await vscode.workspace.fs.stat(resource); + if (stat.size === 0) { + // The file is stored on git lfs + return null; + } + } + + // Avoid adding cache busting if there is already a query string + if (resource.query) { + return webviewEditor.webview.asWebviewUri(resource).toString(); + } + return webviewEditor.webview.asWebviewUri(resource).with({ query: `version=${version}` }).toString(); + } + + private extensionResource(...parts: string[]) { + return this.webviewEditor.webview.asWebviewUri(vscode.Uri.joinPath(this.extensionRoot, ...parts)); + } +} + +export function registerAudioPreviewSupport(context: vscode.ExtensionContext, binarySizeStatusBarEntry: BinarySizeStatusBarEntry): vscode.Disposable { + const provider = new AudioPreviewProvider(context.extensionUri, binarySizeStatusBarEntry); + return vscode.window.registerCustomEditorProvider(AudioPreviewProvider.viewType, provider, { + supportsMultipleEditorsPerDocument: true, + webviewOptions: { + retainContextWhenHidden: true, + } + }); +} diff --git a/extensions/image-preview/src/binarySizeStatusBarEntry.ts b/extensions/image-preview/src/binarySizeStatusBarEntry.ts index ce375fc19b8..da41ccfe5e5 100644 --- a/extensions/image-preview/src/binarySizeStatusBarEntry.ts +++ b/extensions/image-preview/src/binarySizeStatusBarEntry.ts @@ -42,7 +42,7 @@ export class BinarySizeStatusBarEntry extends PreviewStatusBarEntry { super('status.imagePreview.binarySize', localize('sizeStatusBar.name', "Image Binary Size"), vscode.StatusBarAlignment.Right, 100); } - public show(owner: string, size: number | undefined) { + public show(owner: unknown, size: number | undefined) { if (typeof size === 'number') { super.showItem(owner, BinarySize.formatSize(size)); } else { diff --git a/extensions/image-preview/src/extension.ts b/extensions/image-preview/src/extension.ts index 10722360dd5..31370d48fc6 100644 --- a/extensions/image-preview/src/extension.ts +++ b/extensions/image-preview/src/extension.ts @@ -4,32 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import { registerAudioPreviewSupport } from './audioPreview'; import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry'; -import { PreviewManager } from './preview'; -import { SizeStatusBarEntry } from './sizeStatusBarEntry'; -import { ZoomStatusBarEntry } from './zoomStatusBarEntry'; +import { registerImagePreviewSupport } from './imagePreview'; +import { registerVideoPreviewSupport } from './videoPreview'; export function activate(context: vscode.ExtensionContext) { - const sizeStatusBarEntry = new SizeStatusBarEntry(); - context.subscriptions.push(sizeStatusBarEntry); - const binarySizeStatusBarEntry = new BinarySizeStatusBarEntry(); context.subscriptions.push(binarySizeStatusBarEntry); - const zoomStatusBarEntry = new ZoomStatusBarEntry(); - context.subscriptions.push(zoomStatusBarEntry); - - const previewManager = new PreviewManager(context.extensionUri, sizeStatusBarEntry, binarySizeStatusBarEntry, zoomStatusBarEntry); - - context.subscriptions.push(vscode.window.registerCustomEditorProvider(PreviewManager.viewType, previewManager, { - supportsMultipleEditorsPerDocument: true, - })); - - context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => { - previewManager.activePreview?.zoomIn(); - })); - - context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomOut', () => { - previewManager.activePreview?.zoomOut(); - })); + context.subscriptions.push(registerImagePreviewSupport(context, binarySizeStatusBarEntry)); + context.subscriptions.push(registerAudioPreviewSupport(context, binarySizeStatusBarEntry)); + context.subscriptions.push(registerVideoPreviewSupport(context, binarySizeStatusBarEntry)); } diff --git a/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/imagePreview/index.ts similarity index 54% rename from extensions/image-preview/src/preview.ts rename to extensions/image-preview/src/imagePreview/index.ts index 94521f1f8e1..37dc18c4c0f 100644 --- a/extensions/image-preview/src/preview.ts +++ b/extensions/image-preview/src/imagePreview/index.ts @@ -5,10 +5,11 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; -import { Disposable } from './dispose'; +import { BinarySizeStatusBarEntry } from '../binarySizeStatusBarEntry'; +import { MediaPreview, PreviewState, reopenAsText } from '../mediaPreview'; +import { escapeAttribute, getNonce } from '../util/dom'; import { SizeStatusBarEntry } from './sizeStatusBarEntry'; import { Scale, ZoomStatusBarEntry } from './zoomStatusBarEntry'; -import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry'; const localize = nls.loadMessageBundle(); @@ -16,8 +17,8 @@ export class PreviewManager implements vscode.CustomReadonlyEditorProvider { public static readonly viewType = 'imagePreview.previewEditor'; - private readonly _previews = new Set(); - private _activePreview: Preview | undefined; + private readonly _previews = new Set(); + private _activePreview: ImagePreview | undefined; constructor( private readonly extensionRoot: vscode.Uri, @@ -34,7 +35,7 @@ export class PreviewManager implements vscode.CustomReadonlyEditorProvider { document: vscode.CustomDocument, webviewEditor: vscode.WebviewPanel, ): Promise { - const preview = new Preview(this.extensionRoot, document.uri, webviewEditor, this.sizeStatusBarEntry, this.binarySizeStatusBarEntry, this.zoomStatusBarEntry); + const preview = new ImagePreview(this.extensionRoot, document.uri, webviewEditor, this.sizeStatusBarEntry, this.binarySizeStatusBarEntry, this.zoomStatusBarEntry); this._previews.add(preview); this.setActivePreview(preview); @@ -51,159 +52,102 @@ export class PreviewManager implements vscode.CustomReadonlyEditorProvider { public get activePreview() { return this._activePreview; } - private setActivePreview(value: Preview | undefined): void { + private setActivePreview(value: ImagePreview | 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 { +class ImagePreview extends MediaPreview { - private readonly id: string = `${Date.now()}-${Math.random().toString()}`; - - private _previewState = PreviewState.Visible; private _imageSize: string | undefined; - private _imageBinarySize: number | undefined; private _imageZoom: Scale | undefined; private readonly emptyPngDataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAEElEQVR42gEFAPr/AP///wAI/AL+Sr4t6gAAAABJRU5ErkJggg=='; constructor( private readonly extensionRoot: vscode.Uri, - private readonly resource: vscode.Uri, - private readonly webviewEditor: vscode.WebviewPanel, + resource: vscode.Uri, + webviewEditor: vscode.WebviewPanel, private readonly sizeStatusBarEntry: SizeStatusBarEntry, - private readonly binarySizeStatusBarEntry: BinarySizeStatusBarEntry, + binarySizeStatusBarEntry: BinarySizeStatusBarEntry, private readonly zoomStatusBarEntry: ZoomStatusBarEntry, ) { - super(); - const resourceRoot = resource.with({ - path: resource.path.replace(/\/[^\/]+?\.\w+$/, '/'), - }); - - webviewEditor.webview.options = { - enableScripts: true, - enableForms: false, - localResourceRoots: [ - resourceRoot, - extensionRoot, - ] - }; + super(extensionRoot, resource, webviewEditor, binarySizeStatusBarEntry); this._register(webviewEditor.webview.onDidReceiveMessage(message => { switch (message.type) { - case 'size': - { - this._imageSize = message.value; - this.update(); - break; - } - case 'zoom': - { - this._imageZoom = message.value; - this.update(); - break; - } - - case 'reopen-as-text': - { - vscode.commands.executeCommand('vscode.openWith', resource, 'default', webviewEditor.viewColumn); - break; - } + case 'size': { + this._imageSize = message.value; + this.updateState(); + break; + } + case 'zoom': { + this._imageZoom = message.value; + this.updateState(); + break; + } + case 'reopen-as-text': { + reopenAsText(resource, webviewEditor.viewColumn); + break; + } } })); this._register(zoomStatusBarEntry.onDidChangeScale(e => { - if (this._previewState === PreviewState.Active) { + if (this.previewState === PreviewState.Active) { this.webviewEditor.webview.postMessage({ type: 'setScale', scale: e.scale }); } })); this._register(webviewEditor.onDidChangeViewState(() => { - this.update(); this.webviewEditor.webview.postMessage({ type: 'setActive', value: this.webviewEditor.active }); })); this._register(webviewEditor.onDidDispose(() => { - if (this._previewState === PreviewState.Active) { - this.sizeStatusBarEntry.hide(this.id); - this.binarySizeStatusBarEntry.hide(this.id); - this.zoomStatusBarEntry.hide(this.id); + if (this.previewState === PreviewState.Active) { + this.sizeStatusBarEntry.hide(this); + this.zoomStatusBarEntry.hide(this); } - this._previewState = PreviewState.Disposed; + this.previewState = PreviewState.Disposed; })); - const watcher = this._register(vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(resource, '*'))); - 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(); - } - })); - - vscode.workspace.fs.stat(resource).then(({ size }) => { - this._imageBinarySize = size; - this.update(); - }); - + this.updateBinarySize(); this.render(); - this.update(); + this.updateState(); + this.webviewEditor.webview.postMessage({ type: 'setActive', value: this.webviewEditor.active }); } public zoomIn() { - if (this._previewState === PreviewState.Active) { + if (this.previewState === PreviewState.Active) { this.webviewEditor.webview.postMessage({ type: 'zoomIn' }); } } public zoomOut() { - if (this._previewState === PreviewState.Active) { + if (this.previewState === PreviewState.Active) { this.webviewEditor.webview.postMessage({ type: 'zoomOut' }); } } - private async render() { - if (this._previewState !== PreviewState.Disposed) { - this.webviewEditor.webview.html = await this.getWebviewContents(); - } - } + protected override updateState() { + super.updateState(); - private update() { - if (this._previewState === PreviewState.Disposed) { + if (this.previewState === PreviewState.Disposed) { return; } if (this.webviewEditor.active) { - this._previewState = PreviewState.Active; - this.sizeStatusBarEntry.show(this.id, this._imageSize || ''); - this.binarySizeStatusBarEntry.show(this.id, this._imageBinarySize); - this.zoomStatusBarEntry.show(this.id, this._imageZoom || 'fit'); + this.sizeStatusBarEntry.show(this, this._imageSize || ''); + this.zoomStatusBarEntry.show(this, this._imageZoom || 'fit'); } else { - if (this._previewState === PreviewState.Active) { - this.sizeStatusBarEntry.hide(this.id); - this.binarySizeStatusBarEntry.hide(this.id); - this.zoomStatusBarEntry.hide(this.id); - } - this._previewState = PreviewState.Visible; + this.sizeStatusBarEntry.hide(this); + this.zoomStatusBarEntry.hide(this); } } - private async getWebviewContents(): Promise { + protected override async getWebviewContents(): Promise { const version = Date.now().toString(); const settings = { src: await this.getResourcePath(this.webviewEditor, this.resource, version), @@ -223,7 +167,7 @@ class Preview extends Disposable { Image Preview - + @@ -234,7 +178,7 @@ class Preview extends Disposable {

${localize('preview.imageLoadError', "An error occurred while loading the image.")}

${localize('preview.imageLoadErrorLink', "Open file using VS Code's standard text/binary editor?")} - + `; } @@ -254,22 +198,34 @@ class Preview extends Disposable { return webviewEditor.webview.asWebviewUri(resource).with({ query: `version=${version}` }).toString(); } - private extensionResource(path: string) { - return this.webviewEditor.webview.asWebviewUri(this.extensionRoot.with({ - path: this.extensionRoot.path + path - })); + private extensionResource(...parts: string[]) { + return this.webviewEditor.webview.asWebviewUri(vscode.Uri.joinPath(this.extensionRoot, ...parts)); } } -function escapeAttribute(value: string | vscode.Uri): string { - return value.toString().replace(/"/g, '"'); -} -function getNonce() { - let text = ''; - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < 64; i++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)); - } - return text; +export function registerImagePreviewSupport(context: vscode.ExtensionContext, binarySizeStatusBarEntry: BinarySizeStatusBarEntry): vscode.Disposable { + const disposables: vscode.Disposable[] = []; + + const sizeStatusBarEntry = new SizeStatusBarEntry(); + disposables.push(sizeStatusBarEntry); + + const zoomStatusBarEntry = new ZoomStatusBarEntry(); + disposables.push(zoomStatusBarEntry); + + const previewManager = new PreviewManager(context.extensionUri, sizeStatusBarEntry, binarySizeStatusBarEntry, zoomStatusBarEntry); + + disposables.push(vscode.window.registerCustomEditorProvider(PreviewManager.viewType, previewManager, { + supportsMultipleEditorsPerDocument: true, + })); + + disposables.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => { + previewManager.activePreview?.zoomIn(); + })); + + disposables.push(vscode.commands.registerCommand('imagePreview.zoomOut', () => { + previewManager.activePreview?.zoomOut(); + })); + + return vscode.Disposable.from(...disposables); } diff --git a/extensions/image-preview/src/sizeStatusBarEntry.ts b/extensions/image-preview/src/imagePreview/sizeStatusBarEntry.ts similarity index 87% rename from extensions/image-preview/src/sizeStatusBarEntry.ts rename to extensions/image-preview/src/imagePreview/sizeStatusBarEntry.ts index 68e5c34d232..397a2ffd97a 100644 --- a/extensions/image-preview/src/sizeStatusBarEntry.ts +++ b/extensions/image-preview/src/imagePreview/sizeStatusBarEntry.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; -import { PreviewStatusBarEntry } from './ownedStatusBarEntry'; +import { PreviewStatusBarEntry } from '../ownedStatusBarEntry'; const localize = nls.loadMessageBundle(); @@ -15,7 +15,7 @@ export class SizeStatusBarEntry extends PreviewStatusBarEntry { super('status.imagePreview.size', localize('sizeStatusBar.name', "Image Size"), vscode.StatusBarAlignment.Right, 101 /* to the left of editor status (100) */); } - public show(owner: string, text: string) { + public show(owner: unknown, text: string) { this.showItem(owner, text); } } diff --git a/extensions/image-preview/src/zoomStatusBarEntry.ts b/extensions/image-preview/src/imagePreview/zoomStatusBarEntry.ts similarity index 93% rename from extensions/image-preview/src/zoomStatusBarEntry.ts rename to extensions/image-preview/src/imagePreview/zoomStatusBarEntry.ts index a4fcdc2b604..de0729bebf1 100644 --- a/extensions/image-preview/src/zoomStatusBarEntry.ts +++ b/extensions/image-preview/src/imagePreview/zoomStatusBarEntry.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; -import { PreviewStatusBarEntry as OwnedStatusBarEntry } from './ownedStatusBarEntry'; +import { PreviewStatusBarEntry as OwnedStatusBarEntry } from '../ownedStatusBarEntry'; const localize = nls.loadMessageBundle(); @@ -41,7 +41,7 @@ export class ZoomStatusBarEntry extends OwnedStatusBarEntry { this.entry.command = selectZoomLevelCommandId; } - public show(owner: string, scale: Scale) { + public show(owner: unknown, scale: Scale) { this.showItem(owner, this.zoomLabel(scale)); } diff --git a/extensions/image-preview/src/mediaPreview.ts b/extensions/image-preview/src/mediaPreview.ts new file mode 100644 index 00000000000..7c56c3fe6ae --- /dev/null +++ b/extensions/image-preview/src/mediaPreview.ts @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry'; +import { Disposable } from './util/dispose'; + +export function reopenAsText(resource: vscode.Uri, viewColumn: vscode.ViewColumn | undefined) { + vscode.commands.executeCommand('vscode.openWith', resource, 'default', viewColumn); +} + +export const enum PreviewState { + Disposed, + Visible, + Active, +} + +export abstract class MediaPreview extends Disposable { + + protected previewState = PreviewState.Visible; + private _binarySize: number | undefined; + + constructor( + extensionRoot: vscode.Uri, + protected readonly resource: vscode.Uri, + protected readonly webviewEditor: vscode.WebviewPanel, + private readonly binarySizeStatusBarEntry: BinarySizeStatusBarEntry, + ) { + super(); + + const resourceRoot = resource.with({ + path: resource.path.replace(/\/[^\/]+?\.\w+$/, '/'), + }); + + webviewEditor.webview.options = { + enableScripts: true, + enableForms: false, + localResourceRoots: [ + resourceRoot, + extensionRoot, + ] + }; + + this._register(webviewEditor.onDidChangeViewState(() => { + this.updateState(); + })); + + this._register(webviewEditor.onDidDispose(() => { + if (this.previewState === PreviewState.Active) { + this.binarySizeStatusBarEntry.hide(this); + } + this.previewState = PreviewState.Disposed; + })); + + const watcher = this._register(vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(resource, '*'))); + this._register(watcher.onDidChange(e => { + if (e.toString() === this.resource.toString()) { + this.updateBinarySize(); + this.render(); + } + })); + + this._register(watcher.onDidDelete(e => { + if (e.toString() === this.resource.toString()) { + this.webviewEditor.dispose(); + } + })); + } + + protected updateBinarySize() { + vscode.workspace.fs.stat(this.resource).then(({ size }) => { + this._binarySize = size; + this.updateState(); + }); + } + + protected async render() { + if (this.previewState === PreviewState.Disposed) { + return; + } + + const content = await this.getWebviewContents(); + if (this.previewState as PreviewState === PreviewState.Disposed) { + return; + } + + this.webviewEditor.webview.html = content; + } + + protected abstract getWebviewContents(): Promise; + + protected updateState() { + if (this.previewState === PreviewState.Disposed) { + return; + } + + if (this.webviewEditor.active) { + this.previewState = PreviewState.Active; + this.binarySizeStatusBarEntry.show(this, this._binarySize); + } else { + this.binarySizeStatusBarEntry.hide(this); + this.previewState = PreviewState.Visible; + } + } +} diff --git a/extensions/image-preview/src/ownedStatusBarEntry.ts b/extensions/image-preview/src/ownedStatusBarEntry.ts index 31165f67d69..fff43b572ba 100644 --- a/extensions/image-preview/src/ownedStatusBarEntry.ts +++ b/extensions/image-preview/src/ownedStatusBarEntry.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { Disposable } from './dispose'; +import { Disposable } from './util/dispose'; export abstract class PreviewStatusBarEntry extends Disposable { - private _showOwner: string | undefined; + private _showOwner: unknown | undefined; protected readonly entry: vscode.StatusBarItem; @@ -17,13 +17,13 @@ export abstract class PreviewStatusBarEntry extends Disposable { this.entry.name = name; } - protected showItem(owner: string, text: string) { + protected showItem(owner: unknown, text: string) { this._showOwner = owner; this.entry.text = text; this.entry.show(); } - public hide(owner: string) { + public hide(owner: unknown) { if (owner === this._showOwner) { this.entry.hide(); this._showOwner = undefined; diff --git a/extensions/image-preview/src/dispose.ts b/extensions/image-preview/src/util/dispose.ts similarity index 100% rename from extensions/image-preview/src/dispose.ts rename to extensions/image-preview/src/util/dispose.ts diff --git a/extensions/image-preview/src/util/dom.ts b/extensions/image-preview/src/util/dom.ts new file mode 100644 index 00000000000..0f6c00da9da --- /dev/null +++ b/extensions/image-preview/src/util/dom.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as vscode from 'vscode'; + +export function escapeAttribute(value: string | vscode.Uri): string { + return value.toString().replace(/"/g, '"'); +} + +export function getNonce() { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 64; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} diff --git a/extensions/image-preview/src/videoPreview.ts b/extensions/image-preview/src/videoPreview.ts new file mode 100644 index 00000000000..386984ff1e6 --- /dev/null +++ b/extensions/image-preview/src/videoPreview.ts @@ -0,0 +1,122 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; +import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry'; +import { MediaPreview, reopenAsText } from './mediaPreview'; +import { escapeAttribute, getNonce } from './util/dom'; + +const localize = nls.loadMessageBundle(); + +class VideoPreviewProvider implements vscode.CustomReadonlyEditorProvider { + + public static readonly viewType = 'vscode.videoPreview'; + + constructor( + private readonly extensionRoot: vscode.Uri, + private readonly binarySizeStatusBarEntry: BinarySizeStatusBarEntry, + ) { } + + public async openCustomDocument(uri: vscode.Uri) { + return { uri, dispose: () => { } }; + } + + public async resolveCustomEditor(document: vscode.CustomDocument, webviewEditor: vscode.WebviewPanel): Promise { + new VideoPreview(this.extensionRoot, document.uri, webviewEditor, this.binarySizeStatusBarEntry); + } +} + + +class VideoPreview extends MediaPreview { + + constructor( + private readonly extensionRoot: vscode.Uri, + resource: vscode.Uri, + webviewEditor: vscode.WebviewPanel, + binarySizeStatusBarEntry: BinarySizeStatusBarEntry, + ) { + super(extensionRoot, resource, webviewEditor, binarySizeStatusBarEntry); + + this._register(webviewEditor.webview.onDidReceiveMessage(message => { + switch (message.type) { + case 'reopen-as-text': { + reopenAsText(resource, webviewEditor.viewColumn); + break; + } + } + })); + + this.updateBinarySize(); + this.render(); + this.updateState(); + } + + protected async getWebviewContents(): Promise { + const version = Date.now().toString(); + const settings = { + src: await this.getResourcePath(this.webviewEditor, this.resource, version), + }; + + const nonce = getNonce(); + + const cspSource = this.webviewEditor.webview.cspSource; + return /* html */` + + + + + + + + Video Preview + + + + + + + +
+
+

${localize('preview.videoLoadError', "An error occurred while loading the video file.")}

+ ${localize('preview.videoLoadErrorLink', "Open file using VS Code's standard text/binary editor?")} +
+ + +`; + } + + private async getResourcePath(webviewEditor: vscode.WebviewPanel, resource: vscode.Uri, version: string): Promise { + if (resource.scheme === 'git') { + const stat = await vscode.workspace.fs.stat(resource); + if (stat.size === 0) { + // The file is stored on git lfs + return null; + } + } + + // Avoid adding cache busting if there is already a query string + if (resource.query) { + return webviewEditor.webview.asWebviewUri(resource).toString(); + } + return webviewEditor.webview.asWebviewUri(resource).with({ query: `version=${version}` }).toString(); + } + + private extensionResource(...parts: string[]) { + return this.webviewEditor.webview.asWebviewUri(vscode.Uri.joinPath(this.extensionRoot, ...parts)); + } +} + +export function registerVideoPreviewSupport(context: vscode.ExtensionContext, binarySizeStatusBarEntry: BinarySizeStatusBarEntry): vscode.Disposable { + const provider = new VideoPreviewProvider(context.extensionUri, binarySizeStatusBarEntry); + return vscode.window.registerCustomEditorProvider(VideoPreviewProvider.viewType, provider, { + supportsMultipleEditorsPerDocument: true, + webviewOptions: { + retainContextWhenHidden: true, + } + }); +} diff --git a/extensions/image-preview/yarn.lock b/extensions/image-preview/yarn.lock index 65af1b8b351..61a6bb946db 100644 --- a/extensions/image-preview/yarn.lock +++ b/extensions/image-preview/yarn.lock @@ -2,12 +2,51 @@ # yarn lockfile v1 -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" + +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/ini/package.json b/extensions/ini/package.json index 324e4c87f6e..aa98ee3a353 100644 --- a/extensions/ini/package.json +++ b/extensions/ini/package.json @@ -37,7 +37,8 @@ ".editorconfig" ], "filenames": [ - "gitconfig" + "gitconfig", + ".env" ], "filenamePatterns": [ "**/.config/git/config", diff --git a/extensions/ipynb/.gitignore b/extensions/ipynb/.gitignore index 170d890802b..8c0ca40ca20 100644 --- a/extensions/ipynb/.gitignore +++ b/extensions/ipynb/.gitignore @@ -2,3 +2,4 @@ out dist node_modules *.vsix +notebook-out diff --git a/extensions/ipynb/.vscodeignore b/extensions/ipynb/.vscodeignore index 08245c01482..69a1b29e0ce 100644 --- a/extensions/ipynb/.vscodeignore +++ b/extensions/ipynb/.vscodeignore @@ -1,9 +1,10 @@ .vscode/** src/** +notebook-src/** out/** tsconfig.json extension.webpack.config.js extension-browser.webpack.config.js yarn.lock .gitignore - +esbuild.js diff --git a/extensions/ipynb/esbuild.js b/extensions/ipynb/esbuild.js new file mode 100644 index 00000000000..4128889bf76 --- /dev/null +++ b/extensions/ipynb/esbuild.js @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +//@ts-check + +const path = require('path'); +const fse = require('fs-extra'); +const esbuild = require('esbuild'); + +const args = process.argv.slice(2); + +const isWatch = args.indexOf('--watch') >= 0; + +let outputRoot = __dirname; +const outputRootIndex = args.indexOf('--outputRoot'); +if (outputRootIndex >= 0) { + outputRoot = args[outputRootIndex + 1]; +} + +const srcDir = path.join(__dirname, 'notebook-src'); +const outDir = path.join(outputRoot, 'notebook-out'); + +async function build() { + await esbuild.build({ + entryPoints: [ + path.join(srcDir, 'cellAttachmentRenderer.ts'), + ], + bundle: true, + minify: false, + sourcemap: false, + format: 'esm', + outdir: outDir, + platform: 'browser', + target: ['es2020'], + }); +} + + +build().catch(() => process.exit(1)); + +if (isWatch) { + const watcher = require('@parcel/watcher'); + watcher.subscribe(srcDir, () => { + return build(); + }); +} diff --git a/extensions/ipynb/notebook-src/cellAttachmentRenderer.ts b/extensions/ipynb/notebook-src/cellAttachmentRenderer.ts new file mode 100644 index 00000000000..722f6182708 --- /dev/null +++ b/extensions/ipynb/notebook-src/cellAttachmentRenderer.ts @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type * as MarkdownIt from 'markdown-it'; +import type * as MarkdownItToken from 'markdown-it/lib/token'; +import type { RendererContext } from 'vscode-notebook-renderer'; + +interface MarkdownItRenderer { + extendMarkdownIt(fn: (md: MarkdownIt) => void): void; +} + +export async function activate(ctx: RendererContext) { + const markdownItRenderer = (await ctx.getRenderer('vscode.markdown-it-renderer')) as MarkdownItRenderer | any; + if (!markdownItRenderer) { + throw new Error(`Could not load 'vscode.markdown-it-renderer'`); + } + + markdownItRenderer.extendMarkdownIt((md: MarkdownIt) => { + const original = md.renderer.rules.image; + md.renderer.rules.image = (tokens: MarkdownItToken[], idx: number, options, env, self) => { + const token = tokens[idx]; + const src = token.attrGet('src'); + const attachments: Record> = env.outputItem.metadata.custom?.attachments; + if (attachments && src) { + const imageAttachment = attachments[src.replace('attachment:', '')]; + if (imageAttachment) { + // objEntries will always be length 1, with objEntries[0] holding [0]=mime,[1]=b64 + // if length = 0, something is wrong with the attachment, mime/b64 weren't copied over + const objEntries = Object.entries(imageAttachment); + if (objEntries.length) { + const [attachmentKey, attachmentVal] = objEntries[0]; + const b64Markdown = 'data:' + attachmentKey + ';base64,' + attachmentVal; + token.attrSet('src', b64Markdown); + } + } + } + + if (original) { + return original(tokens, idx, options, env, self); + } else { + return self.renderToken(tokens, idx, options); + } + }; + }); +} diff --git a/extensions/ipynb/package.json b/extensions/ipynb/package.json index 1e251a5a19b..7814fb7241f 100644 --- a/extensions/ipynb/package.json +++ b/extensions/ipynb/package.json @@ -9,7 +9,7 @@ "vscode": "^1.57.0" }, "enabledApiProposals": [ - "notebookWorkspaceEdit" + "documentPaste" ], "activationEvents": [ "*" @@ -27,6 +27,21 @@ } }, "contributes": { + "configuration":[ + { + "properties": { + "ipynb.experimental.pasteImages.enabled":{ + "type": "boolean", + "scope": "resource", + "markdownDescription": "%ipynb.experimental.pasteImages.enabled%", + "default": false, + "tags": [ + "experimental" + ] + } + } + } + ], "commands": [ { "command": "ipynb.newUntitledIpynb", @@ -51,6 +66,16 @@ "priority": "default" } ], + "notebookRenderer": [ + { + "id": "vscode.markdown-it-cell-attachment-renderer", + "displayName": "Markdown it ipynb Cell Attachment renderer", + "entrypoint": { + "extends": "vscode.markdown-it-renderer", + "path": "./notebook-out/cellAttachmentRenderer.js" + } + } + ], "menus": { "file/newFile": [ { @@ -70,8 +95,9 @@ } }, "scripts": { - "compile": "npx gulp compile-extension:ipynb", - "watch": "npx gulp watch-extension:ipynb" + "compile": "npx gulp compile-extension:ipynb && npm run build-notebook", + "watch": "npx gulp watch-extension:ipynb", + "build-notebook": "node ./esbuild" }, "dependencies": { "@enonic/fnv-plus": "^1.3.0", @@ -80,6 +106,7 @@ }, "devDependencies": { "@jupyterlab/nbformat": "^3.2.9", + "@types/markdown-it": "12.2.3", "@types/uuid": "^8.3.1" }, "repository": { diff --git a/extensions/ipynb/package.nls.json b/extensions/ipynb/package.nls.json index 6f2f7e47c0c..e003f299b56 100644 --- a/extensions/ipynb/package.nls.json +++ b/extensions/ipynb/package.nls.json @@ -1,4 +1,5 @@ { "displayName": ".ipynb support", - "description": "Provides basic support for opening and reading Jupyter's .ipynb notebook files" + "description": "Provides basic support for opening and reading Jupyter's .ipynb notebook files", + "ipynb.experimental.pasteImages.enabled":"Enable/Disable pasting images into markdown cells within ipynb files. Requires enabling `#editor.experimental.pasteActions.enabled#`." } diff --git a/extensions/ipynb/src/cellIdService.ts b/extensions/ipynb/src/cellIdService.ts index ddda0a9fd5f..2eccb586ef4 100644 --- a/extensions/ipynb/src/cellIdService.ts +++ b/extensions/ipynb/src/cellIdService.ts @@ -8,7 +8,7 @@ import { v4 as uuid } from 'uuid'; import { getCellMetadata } from './serializers'; import { CellMetadata } from './common'; import { getNotebookMetadata } from './notebookSerializer'; -import * as nbformat from '@jupyterlab/nbformat'; +import type * as nbformat from '@jupyterlab/nbformat'; /** * Ensure all new cells in notebooks with nbformat >= 4.5 have an id. diff --git a/extensions/ipynb/src/common.ts b/extensions/ipynb/src/common.ts index de72fbbbfc3..d5ff5f86069 100644 --- a/extensions/ipynb/src/common.ts +++ b/extensions/ipynb/src/common.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nbformat from '@jupyterlab/nbformat'; +import type * as nbformat from '@jupyterlab/nbformat'; /** * Metadata we store in VS Code cell output items. @@ -44,7 +44,7 @@ export interface CellOutputMetadata { /** * Metadata we store in VS Code cells. - * This contains the original metadata from the Jupyuter cells. + * This contains the original metadata from the Jupyter cells. */ export interface CellMetadata { /** diff --git a/extensions/ipynb/src/deserializers.ts b/extensions/ipynb/src/deserializers.ts index 50a3a1271b0..92cd20bb33a 100644 --- a/extensions/ipynb/src/deserializers.ts +++ b/extensions/ipynb/src/deserializers.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nbformat from '@jupyterlab/nbformat'; +import type * as nbformat from '@jupyterlab/nbformat'; import { extensions, NotebookCellData, NotebookCellExecutionSummary, NotebookCellKind, NotebookCellOutput, NotebookCellOutputItem, NotebookData } from 'vscode'; import { CellMetadata, CellOutputMetadata } from './common'; diff --git a/extensions/ipynb/src/ipynbMain.ts b/extensions/ipynb/src/ipynbMain.ts index 33bb1456af8..003c4c8f266 100644 --- a/extensions/ipynb/src/ipynbMain.ts +++ b/extensions/ipynb/src/ipynbMain.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; import { ensureAllNewCellsHaveCellIds } from './cellIdService'; import { NotebookSerializer } from './notebookSerializer'; +import * as NotebookImagePaste from './notebookImagePaste'; // From {nbformat.INotebookMetadata} in @jupyterlab/coreutils type NotebookMetadata = { @@ -77,12 +78,15 @@ export function activate(context: vscode.ExtensionContext) { await vscode.window.showNotebookDocument(document); })); + context.subscriptions.push(NotebookImagePaste.imagePasteSetup()); + // Update new file contribution vscode.extensions.onDidChange(() => { vscode.commands.executeCommand('setContext', 'jupyterEnabled', vscode.extensions.getExtension('ms-toolsai.jupyter')); }); vscode.commands.executeCommand('setContext', 'jupyterEnabled', vscode.extensions.getExtension('ms-toolsai.jupyter')); + return { exportNotebook: (notebook: vscode.NotebookData): string => { return exportNotebook(notebook, serializer); diff --git a/extensions/ipynb/src/notebookImagePaste.ts b/extensions/ipynb/src/notebookImagePaste.ts new file mode 100644 index 00000000000..bf2c8b4467e --- /dev/null +++ b/extensions/ipynb/src/notebookImagePaste.ts @@ -0,0 +1,158 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +class CopyPasteEditProvider implements vscode.DocumentPasteEditProvider { + + async provideDocumentPasteEdits( + document: vscode.TextDocument, + _ranges: readonly vscode.Range[], + dataTransfer: vscode.DataTransfer, + _token: vscode.CancellationToken + ): Promise { + + const enabled = vscode.workspace.getConfiguration('ipynb', document).get('experimental.pasteImages.enabled', false); + if (!enabled) { + return undefined; + } + + // get b64 data from paste + // TODO: dataTransfer.get() limits to one image pasted + const dataItem = dataTransfer.get('image/png'); + if (!dataItem) { + return undefined; + } + const fileDataAsUint8 = await dataItem.asFile()?.data(); + if (!fileDataAsUint8) { + return undefined; + } + + // get filename data from paste + const clipboardFilename = dataItem.asFile()?.name; + if (!clipboardFilename) { + return undefined; + } + const separatorIndex = clipboardFilename?.lastIndexOf('.'); + const filename = clipboardFilename?.slice(0, separatorIndex); + const filetype = clipboardFilename?.slice(separatorIndex); + if (!filename || !filetype) { + return undefined; + } + + const currentCell = this.getCellFromCellDocument(document); + if (!currentCell) { + return undefined; + } + const notebookUri = currentCell.notebook.uri; + + // create updated metadata for cell (prep for WorkspaceEdit) + const b64string = encodeBase64(fileDataAsUint8); + const startingAttachments = currentCell.metadata.custom?.attachments; + const newAttachment = buildAttachment(b64string, currentCell, filename, filetype, startingAttachments); + + // build edits + const nbEdit = vscode.NotebookEdit.updateCellMetadata(currentCell.index, newAttachment.metadata); + const workspaceEdit = new vscode.WorkspaceEdit(); + workspaceEdit.set(notebookUri, [nbEdit]); + + // create a snippet for paste + const pasteSnippet = new vscode.SnippetString(); + pasteSnippet.appendText('!['); + pasteSnippet.appendPlaceholder(`${clipboardFilename}`); + pasteSnippet.appendText(`](attachment:${newAttachment.filename})`); + + return { insertText: pasteSnippet, additionalEdit: workspaceEdit }; + } + + private getCellFromCellDocument(cellDocument: vscode.TextDocument): vscode.NotebookCell | undefined { + for (const notebook of vscode.workspace.notebookDocuments) { + if (notebook.uri.path === cellDocument.uri.path) { + for (const cell of notebook.getCells()) { + if (cell.document === cellDocument) { + return cell; + } + } + } + } + return undefined; + } +} + +/** + * Taken from https://github.com/microsoft/vscode/blob/743b016722db90df977feecde0a4b3b4f58c2a4c/src/vs/base/common/buffer.ts#L350-L387 + */ +function encodeBase64(buffer: Uint8Array, padded = true, urlSafe = false) { + const base64Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + const base64UrlSafeAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; + + const dictionary = urlSafe ? base64UrlSafeAlphabet : base64Alphabet; + let output = ''; + + const remainder = buffer.byteLength % 3; + + let i = 0; + for (; i < buffer.byteLength - remainder; i += 3) { + const a = buffer[i + 0]; + const b = buffer[i + 1]; + const c = buffer[i + 2]; + + output += dictionary[a >>> 2]; + output += dictionary[(a << 4 | b >>> 4) & 0b111111]; + output += dictionary[(b << 2 | c >>> 6) & 0b111111]; + output += dictionary[c & 0b111111]; + } + + if (remainder === 1) { + const a = buffer[i + 0]; + output += dictionary[a >>> 2]; + output += dictionary[(a << 4) & 0b111111]; + if (padded) { output += '=='; } + } else if (remainder === 2) { + const a = buffer[i + 0]; + const b = buffer[i + 1]; + output += dictionary[a >>> 2]; + output += dictionary[(a << 4 | b >>> 4) & 0b111111]; + output += dictionary[(b << 2) & 0b111111]; + if (padded) { output += '='; } + } + + return output; +} + +function buildAttachment(b64: string, cell: vscode.NotebookCell, filename: string, filetype: string, startingAttachments: any): { metadata: { [key: string]: any }; filename: string } { + const outputMetadata = { ...cell.metadata }; + let tempFilename = filename + filetype; + + if (!outputMetadata.custom) { + outputMetadata['custom'] = { 'attachments': { [tempFilename]: { 'image/png': b64 } } }; + } else if (!outputMetadata.custom.attachments) { + outputMetadata.custom['attachments'] = { [tempFilename]: { 'image/png': b64 } }; + } else { + for (let appendValue = 2; tempFilename in startingAttachments; appendValue++) { + const objEntries = Object.entries(startingAttachments[tempFilename]); + if (objEntries.length) { // check that mime:b64 are present + const [, attachmentb64] = objEntries[0]; + if (attachmentb64 === b64) { // checking if filename can be reused, based on camparison of image data + break; + } else { + tempFilename = filename.concat(`-${appendValue}`) + filetype; + } + } + } + outputMetadata.custom.attachments[tempFilename] = { 'image/png': b64 }; + } + return { + metadata: outputMetadata, + filename: tempFilename + }; +} + +export function imagePasteSetup() { + const selector: vscode.DocumentSelector = { notebookType: 'jupyter-notebook', language: 'markdown' }; // this is correct provider + return vscode.languages.registerDocumentPasteEditProvider(selector, new CopyPasteEditProvider(), { + pasteMimeTypes: ['image/png'], + }); +} diff --git a/extensions/ipynb/src/notebookSerializer.ts b/extensions/ipynb/src/notebookSerializer.ts index 37eee49b1be..0c3ccd09723 100644 --- a/extensions/ipynb/src/notebookSerializer.ts +++ b/extensions/ipynb/src/notebookSerializer.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nbformat from '@jupyterlab/nbformat'; +import type * as nbformat from '@jupyterlab/nbformat'; import * as detectIndent from 'detect-indent'; import * as vscode from 'vscode'; import { defaultNotebookFormat } from './constants'; diff --git a/extensions/ipynb/src/serializers.ts b/extensions/ipynb/src/serializers.ts index 078bb408cc5..455fb0d2745 100644 --- a/extensions/ipynb/src/serializers.ts +++ b/extensions/ipynb/src/serializers.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nbformat from '@jupyterlab/nbformat'; +import type * as nbformat from '@jupyterlab/nbformat'; import { NotebookCell, NotebookCellData, NotebookCellKind, NotebookCellOutput } from 'vscode'; import { CellMetadata, CellOutputMetadata } from './common'; import { textMimeTypes } from './deserializers'; diff --git a/extensions/ipynb/src/test/serializers.test.ts b/extensions/ipynb/src/test/serializers.test.ts index 15ef1185f94..2a59c73532e 100644 --- a/extensions/ipynb/src/test/serializers.test.ts +++ b/extensions/ipynb/src/test/serializers.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nbformat from '@jupyterlab/nbformat'; +import type * as nbformat from '@jupyterlab/nbformat'; import * as assert from 'assert'; import * as vscode from 'vscode'; import { jupyterCellOutputToCellOutput, jupyterNotebookModelToNotebookData } from '../deserializers'; diff --git a/extensions/ipynb/tsconfig.json b/extensions/ipynb/tsconfig.json index a8006017458..f440ed24bea 100644 --- a/extensions/ipynb/tsconfig.json +++ b/extensions/ipynb/tsconfig.json @@ -9,6 +9,6 @@ "include": [ "src/**/*", "../../src/vscode-dts/vscode.d.ts", - "../../src/vscode-dts/vscode.proposed.notebookWorkspaceEdit.d.ts" + "../../src/vscode-dts/vscode.proposed.documentPaste.d.ts" ] } diff --git a/extensions/ipynb/yarn.lock b/extensions/ipynb/yarn.lock index c932570ecc0..7b5488e7109 100644 --- a/extensions/ipynb/yarn.lock +++ b/extensions/ipynb/yarn.lock @@ -8,21 +8,39 @@ integrity sha512-BCN9uNWH8AmiP7BXBJqEinUY9KXalmRzo+L0cB/mQsmFfzODxwQrbvxCHXUNH2iP+qKkWYtB4vyy8N62PViMFw== "@jupyterlab/nbformat@^3.2.9": - version "3.2.9" - resolved "https://registry.yarnpkg.com/@jupyterlab/nbformat/-/nbformat-3.2.9.tgz#e7d854719612133498af4280d9a8caa0873205b0" - integrity sha512-WSf9OQo8yfFjyodbXRdFoaNwMkaAL5jFZiD6V2f8HqI380ipansWrrV7R9CGzPfgKHpUGZMO1tYKmUwzMhvZ4w== + version "3.4.3" + resolved "https://registry.yarnpkg.com/@jupyterlab/nbformat/-/nbformat-3.4.3.tgz#cbab1bf507677b7f0f309d8353fc83fe5a973c82" + integrity sha512-i/yADrwhhAJJCUOTa+fEBMyJO7fvX9Y73I0B7V6dQhGcrmrEKLC3wk4yOo63+jRntd5+dupbiOtz3w1ncIXwIA== dependencies: - "@lumino/coreutils" "^1.5.3" + "@lumino/coreutils" "^1.11.0" -"@lumino/coreutils@^1.5.3": +"@lumino/coreutils@^1.11.0": version "1.12.0" resolved "https://registry.yarnpkg.com/@lumino/coreutils/-/coreutils-1.12.0.tgz#fbdef760f736eaf2bd396a5c6fc3a68a4b449b15" integrity sha512-DSglh4ylmLi820CNx9soJmDJCpUgymckdWeGWuN0Ash5g60oQvrQDfosVxEhzmNvtvXv45WZEqSBzDP6E5SEmQ== +"@types/linkify-it@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" + integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== + +"@types/markdown-it@12.2.3": + version "12.2.3" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" + integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ== + dependencies: + "@types/linkify-it" "*" + "@types/mdurl" "*" + +"@types/mdurl@*": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + "@types/uuid@^8.3.1": - version "8.3.1" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" - integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg== + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== detect-indent@^6.0.0: version "6.1.0" diff --git a/extensions/jake/package.json b/extensions/jake/package.json index 0e5ebc4ea8b..5ffa78e3981 100644 --- a/extensions/jake/package.json +++ b/extensions/jake/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:jake" }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/jake/yarn.lock b/extensions/jake/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/jake/yarn.lock +++ b/extensions/jake/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -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@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index e957c06c1b6..1695f820fcc 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/0dfae8cc4807fecfbf8f1add095d9817df824c95", + "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/73af17bf3e45339df06d92751ab366ce96c38516", "name": "JavaScript (with React support)", "scopeName": "source.js", "patterns": [ @@ -3053,7 +3053,7 @@ "name": "keyword.operator.expression.instanceof.js" } }, - "end": "(?<=\\))|(?=[;),}\\]:?\\-\\+\\>]|\\|\\||\\&\\&|\\!\\=\\=|$|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(===|!==|==|!=)|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -5811,10 +5811,6 @@ "name": "punctuation.definition.entity.js" } } - }, - { - "name": "invalid.illegal.bad-ampersand.js", - "match": "&" } ] }, diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json index 90476c2a91e..1f6564185ac 100644 --- a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/0dfae8cc4807fecfbf8f1add095d9817df824c95", + "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/73af17bf3e45339df06d92751ab366ce96c38516", "name": "JavaScript (with React support)", "scopeName": "source.js.jsx", "patterns": [ @@ -3053,7 +3053,7 @@ "name": "keyword.operator.expression.instanceof.js.jsx" } }, - "end": "(?<=\\))|(?=[;),}\\]:?\\-\\+\\>]|\\|\\||\\&\\&|\\!\\=\\=|$|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(===|!==|==|!=)|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -5811,10 +5811,6 @@ "name": "punctuation.definition.entity.js.jsx" } } - }, - { - "name": "invalid.illegal.bad-ampersand.js.jsx", - "match": "&" } ] }, diff --git a/extensions/json-language-features/client/src/jsonClient.ts b/extensions/json-language-features/client/src/jsonClient.ts index c1c761fbca7..87131049763 100644 --- a/extensions/json-language-features/client/src/jsonClient.ts +++ b/extensions/json-language-features/client/src/jsonClient.ts @@ -57,6 +57,7 @@ type Settings = { json?: { schemas?: JSONSchemaSettings[]; format?: { enable?: boolean }; + keepLines?: { enable?: boolean }; validate?: { enable?: boolean }; resultLimit?: number; }; @@ -74,6 +75,7 @@ export type JSONSchemaSettings = { export namespace SettingIds { export const enableFormatter = 'json.format.enable'; + export const enableKeepLines = 'json.format.keepLines'; export const enableValidation = 'json.validate.enable'; export const enableSchemaDownload = 'json.schemaDownload.enable'; export const maxItemsComputed = 'json.maxItemsComputed'; @@ -480,6 +482,7 @@ function getSettings(): Settings { json: { validate: { enable: configuration.get(SettingIds.enableValidation) }, format: { enable: configuration.get(SettingIds.enableFormatter) }, + keepLines: { enable: configuration.get(SettingIds.enableKeepLines) }, schemas: [], resultLimit: resultLimit + 1 // ask for one more so we can detect if the limit has been exceeded } diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 60388c911af..6548db06e11 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -5,7 +5,7 @@ "version": "1.0.0", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "0.10.x" }, @@ -85,6 +85,12 @@ "default": true, "description": "%json.format.enable.desc%" }, + "json.format.keepLines": { + "type": "boolean", + "scope": "window", + "default": false, + "description": "%json.format.keepLines.desc%" + }, "json.trace.server": { "type": "string", "scope": "window", @@ -147,10 +153,10 @@ ] }, "dependencies": { - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "request-light": "^0.5.8", - "vscode-languageclient": "^8.0.2-next.4", - "vscode-nls": "^5.0.1" + "vscode-languageclient": "^8.1.0-next.1", + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/json-language-features/package.nls.json b/extensions/json-language-features/package.nls.json index 8afec56a90f..a0d0a84b32c 100644 --- a/extensions/json-language-features/package.nls.json +++ b/extensions/json-language-features/package.nls.json @@ -7,6 +7,7 @@ "json.schemas.fileMatch.item.desc": "A file pattern that can contain '*' to match against when resolving JSON files to schemas.", "json.schemas.schema.desc": "The schema definition for the given URL. The schema only needs to be provided to avoid accesses to the schema URL.", "json.format.enable.desc": "Enable/disable default JSON formatter", + "json.format.keepLines.desc" : "Keep all existing new lines when formatting.", "json.validate.enable.desc": "Enable/disable JSON validation.", "json.tracing.desc": "Traces the communication between VS Code and the JSON language server.", "json.colorDecorators.enable.desc": "Enables or disables color decorators", diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index ae471f515cd..802325c6225 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -12,10 +12,10 @@ }, "main": "./out/node/jsonServerMain", "dependencies": { - "jsonc-parser": "^3.0.0", + "jsonc-parser": "^3.2.0", "request-light": "^0.5.8", - "vscode-json-languageservice": "^5.0.0", - "vscode-languageserver": "^8.0.2-next.4", + "vscode-json-languageservice": "^5.1.0", + "vscode-languageserver": "^8.1.0-next.1", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/json-language-features/server/src/jsonServer.ts b/extensions/json-language-features/server/src/jsonServer.ts index 1f295409c5e..05910009b3b 100644 --- a/extensions/json-language-features/server/src/jsonServer.ts +++ b/extensions/json-language-features/server/src/jsonServer.ts @@ -184,6 +184,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) json?: { schemas?: JSONSchemaSettings[]; format?: { enable?: boolean }; + keepLines?: { enable?: boolean }; validate?: { enable?: boolean }; resultLimit?: number; }; @@ -205,13 +206,15 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) let schemaAssociations: ISchemaAssociations | SchemaConfiguration[] | undefined = undefined; let formatterRegistrations: Thenable[] | null = null; let validateEnabled = true; + let keepLinesEnabled = false; - // The settings have changed. Is send on server activation as well. + // The settings have changed. Is sent on server activation as well. connection.onDidChangeConfiguration((change) => { const settings = change.settings; runtime.configureHttpRequests?.(settings?.http?.proxy, !!settings.http?.proxyStrictSSL); jsonConfigurationSettings = settings.json?.schemas; validateEnabled = !!settings.json?.validate?.enable; + keepLinesEnabled = settings.json?.keepLines?.enable || false; updateConfiguration(); foldingRangeLimit = Math.trunc(Math.max(settings.json?.resultLimit || foldingRangeLimitDefault, 0)); @@ -386,6 +389,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) }); function onFormat(textDocument: TextDocumentIdentifier, range: Range | undefined, options: FormattingOptions): TextEdit[] { + options.keepLines = keepLinesEnabled; const document = documents.get(textDocument.uri); if (document) { const edits = languageService.format(document, range ?? getFullRange(document), options); diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 83a722965dd..d64405f9d81 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -12,61 +12,66 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -jsonc-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" - integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== +jsonc-parser@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.1.0.tgz#73b8f0e5c940b83d03476bc2e51a20ef0932615d" + integrity sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg== + +jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== request-light@^0.5.8: version "0.5.8" resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.5.8.tgz#8bf73a07242b9e7b601fac2fa5dc22a094abcc27" integrity sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg== -vscode-json-languageservice@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.0.0.tgz#465d76cfe5dfeed4c3d5a2123b50e3f115bb7f78" - integrity sha512-1/+1TJBRFrfCNizmrW0fbIvguKzzO+4ehlqWCCnF7ioSACUGHrYop4ANb+eRnFaCP6fi3+i+llJC5Y5yAvmL6w== +vscode-json-languageservice@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.1.0.tgz#b1f197a60338cb378189fcb41489a84846724dd9" + integrity sha512-D5612D7h/Gh4A0JmdttPveWzT9dur21WXvBHWKPdOt0sLO6ILz8vN6+IzWnvwDOVAEFTpzIAMVMZwbKZkwGGiA== dependencies: - jsonc-parser "^3.0.0" + jsonc-parser "^3.1.0" vscode-languageserver-textdocument "^1.0.4" vscode-languageserver-types "^3.17.1" vscode-nls "^5.0.1" vscode-uri "^3.0.3" -vscode-jsonrpc@8.0.2-next.1: - version "8.0.2-next.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz#6bdc39fd194782032e34047eeefce562941259c6" - integrity sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA== +vscode-jsonrpc@8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0-next.1.tgz#7c38cb1cbd968c409522593004fdac845a55b155" + integrity sha512-FiPG+9TuMIga3t+kkalQytwqMtJu1djI+Pq+Ut2tvAJpcNHDJ0PYdjFv5mgEvTEJLujrYwjWHVkNe+XfHPBD/w== -vscode-languageserver-protocol@3.17.2-next.5: - version "3.17.2-next.5" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.5.tgz#9bc747411c3ce9e1d73c2714bf6555e0199eec26" - integrity sha512-UlH+QL4Q4lX94of/UPDDwwWIkd8w7dtMW4khzvEDUoykiG9tba0iG6V0bAiv8XVpnBIUYjL2FNFiL3zl+TY1Sw== +vscode-languageserver-protocol@3.17.3-next.1: + version "3.17.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3-next.1.tgz#804880c172b4c48d1a48a91c4c23250121effb19" + integrity sha512-vgjvPE0zox+1Fi4ljsSFJ+B3g8wGNbuAEEdulueVdv+R2VHtc06+dgxhWiG4LKPqXwjPDmiuxCnvd2xk3fzTTw== dependencies: - vscode-jsonrpc "8.0.2-next.1" - vscode-languageserver-types "3.17.2-next.2" + vscode-jsonrpc "8.1.0-next.1" + vscode-languageserver-types "3.17.2" vscode-languageserver-textdocument@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== -vscode-languageserver-types@3.17.2-next.2: - version "3.17.2-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" - integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== +vscode-languageserver-types@3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== vscode-languageserver-types@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== -vscode-languageserver@^8.0.2-next.4: - version "8.0.2-next.4" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2-next.4.tgz#c10cc95be06325b56b7ec1d10271c9e4adf3ef07" - integrity sha512-B3roWH4TmJiB6Zh5+r7zu0QdlLqJsPdGo0LeEi6OiLfrHYCDlcI7DNcQ7F17vWmxC3C82SrxMt/EuLBMpKQM0A== +vscode-languageserver@^8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.1.0-next.1.tgz#1c173de554889bd18ca6e20eaf4bdc84164c86b4" + integrity sha512-u14Rk4JgXI+7iS6AEXI2pNc1dWh/5JEXtaqa4TeBECKJlN+5242mbGBBPaHMOE7sSI1Kh66XhEMZJhPYjUfjHw== dependencies: - vscode-languageserver-protocol "3.17.2-next.5" + vscode-languageserver-protocol "3.17.3-next.1" vscode-nls@^5.0.1: version "5.0.1" diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index 7cdc2d2ec2d..f880319e095 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -2,33 +2,66 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node@16.x": version "16.11.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" - concat-map "0.0.1" - -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= lru-cache@^6.0.0: version "6.0.0" @@ -37,56 +70,56 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +minimatch@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" + integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" request-light@^0.5.8: version "0.5.8" resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.5.8.tgz#8bf73a07242b9e7b601fac2fa5dc22a094abcc27" integrity sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg== -semver@^7.3.5: +semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -vscode-jsonrpc@8.0.2-next.1: - version "8.0.2-next.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz#6bdc39fd194782032e34047eeefce562941259c6" - integrity sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA== +vscode-jsonrpc@8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0-next.1.tgz#7c38cb1cbd968c409522593004fdac845a55b155" + integrity sha512-FiPG+9TuMIga3t+kkalQytwqMtJu1djI+Pq+Ut2tvAJpcNHDJ0PYdjFv5mgEvTEJLujrYwjWHVkNe+XfHPBD/w== -vscode-languageclient@^8.0.2-next.4: - version "8.0.2-next.4" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.2-next.4.tgz#87dd364ffbd4356aff3af14e7b557d9fe34d2b67" - integrity sha512-j9BEiCYMN9IoKwYdk9iickV6WNPVGPoVO11SMdoxFnWPIT3y5UAe3qf/WsfA9OdklAIaxxYasfgyKCpBjSPNuw== +vscode-languageclient@^8.1.0-next.1: + version "8.1.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.1.0-next.1.tgz#44b63bc2d215c13f1dea1dc54267a354ea5451cb" + integrity sha512-lJraJ8IrqXr83ZciAs4dN32f9kEPuOb/FqAeUTgnW5cAxo0Qux0/EMgKyU33Qf9LdEI0I9iwRVxQWtawbyUUfg== dependencies: - minimatch "^3.0.4" - semver "^7.3.5" - vscode-languageserver-protocol "3.17.2-next.5" + minimatch "^5.1.0" + semver "^7.3.7" + vscode-languageserver-protocol "3.17.3-next.1" -vscode-languageserver-protocol@3.17.2-next.5: - version "3.17.2-next.5" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.5.tgz#9bc747411c3ce9e1d73c2714bf6555e0199eec26" - integrity sha512-UlH+QL4Q4lX94of/UPDDwwWIkd8w7dtMW4khzvEDUoykiG9tba0iG6V0bAiv8XVpnBIUYjL2FNFiL3zl+TY1Sw== +vscode-languageserver-protocol@3.17.3-next.1: + version "3.17.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3-next.1.tgz#804880c172b4c48d1a48a91c4c23250121effb19" + integrity sha512-vgjvPE0zox+1Fi4ljsSFJ+B3g8wGNbuAEEdulueVdv+R2VHtc06+dgxhWiG4LKPqXwjPDmiuxCnvd2xk3fzTTw== dependencies: - vscode-jsonrpc "8.0.2-next.1" - vscode-languageserver-types "3.17.2-next.2" + vscode-jsonrpc "8.1.0-next.1" + vscode-languageserver-types "3.17.2" -vscode-languageserver-types@3.17.2-next.2: - version "3.17.2-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" - integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== +vscode-languageserver-types@3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== -vscode-nls@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" - integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== yallist@^4.0.0: version "4.0.0" diff --git a/extensions/latex/cgmanifest.json b/extensions/latex/cgmanifest.json index cb6266c338a..766da20f828 100644 --- a/extensions/latex/cgmanifest.json +++ b/extensions/latex/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "jlelong/vscode-latex-basics", "repositoryUrl": "https://github.com/jlelong/vscode-latex-basics", - "commitHash": "8f2c528619535333a2ff12e321fb6f6efcba38e4" + "commitHash": "ffe263692d6096b24e4897650e933c587fa9c55f" } }, "license": "MIT", diff --git a/extensions/latex/syntaxes/LaTeX.tmLanguage.json b/extensions/latex/syntaxes/LaTeX.tmLanguage.json index e2061e78fa2..7cf93fdbe6a 100644 --- a/extensions/latex/syntaxes/LaTeX.tmLanguage.json +++ b/extensions/latex/syntaxes/LaTeX.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/jlelong/vscode-latex-basics/commit/8f2c528619535333a2ff12e321fb6f6efcba38e4", + "version": "https://github.com/jlelong/vscode-latex-basics/commit/6fc051150e918f8e5df7b102977d8d72eedf66f6", "name": "LaTeX", "scopeName": "text.tex.latex", "patterns": [ @@ -119,7 +119,7 @@ "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" } ] } @@ -160,12 +160,12 @@ }, "patterns": [ { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:cpp|c)\\})", + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:c|cpp)\\})", "captures": { "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" } ] } @@ -179,12 +179,31 @@ "end": "(\\\\end\\{minted\\})" }, { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{css\\})", + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:asy|asymptote)\\})", "captures": { "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.asy", + "patterns": [ + { + "include": "source.asy" + } + ], + "end": "(\\\\end\\{minted\\})" + }, + { + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:css)\\})", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" } ] } @@ -198,12 +217,31 @@ "end": "(\\\\end\\{minted\\})" }, { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{html\\})", + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:hs|haskell)\\})", "captures": { "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.haskell", + "patterns": [ + { + "include": "source.haskell" + } + ], + "end": "(\\\\end\\{minted\\})" + }, + { + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:html)\\})", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" } ] } @@ -217,12 +255,31 @@ "end": "(\\\\end\\{minted\\})" }, { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{java\\})", + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:xml)\\})", "captures": { "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "text.xml", + "patterns": [ + { + "include": "text.xml" + } + ], + "end": "(\\\\end\\{minted\\})" + }, + { + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:java)\\})", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" } ] } @@ -235,13 +292,70 @@ ], "end": "(\\\\end\\{minted\\})" }, + { + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:lua)\\})", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.lua", + "patterns": [ + { + "include": "source.lua" + } + ], + "end": "(\\\\end\\{minted\\})" + }, + { + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:jl|julia)\\})", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.julia", + "patterns": [ + { + "include": "source.julia" + } + ], + "end": "(\\\\end\\{minted\\})" + }, + { + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:rb|ruby)\\})", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.ruby", + "patterns": [ + { + "include": "source.ruby" + } + ], + "end": "(\\\\end\\{minted\\})" + }, { "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:js|javascript)\\})", "captures": { "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" } ] } @@ -260,7 +374,7 @@ "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" } ] } @@ -274,31 +388,12 @@ "end": "(\\\\end\\{minted\\})" }, { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{lua\\})", + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:py|python)\\})", "captures": { "1": { "patterns": [ { - "include": "#env-mandatory-arg" - } - ] - } - }, - "contentName": "source.lua", - "patterns": [ - { - "include": "source.lua" - } - ], - "end": "(\\\\end\\{minted\\})" - }, - { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:python|py)\\})", - "captures": { - "1": { - "patterns": [ - { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" } ] } @@ -312,69 +407,12 @@ "end": "(\\\\end\\{minted\\})" }, { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(julia)\\})", + "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(?:yaml)\\})", "captures": { "1": { "patterns": [ { - "include": "#env-mandatory-arg" - } - ] - } - }, - "contentName": "source.julia", - "patterns": [ - { - "include": "source.julia" - } - ], - "end": "(\\\\end\\{minted\\})" - }, - { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{(ruby)\\})", - "captures": { - "1": { - "patterns": [ - { - "include": "#env-mandatory-arg" - } - ] - } - }, - "contentName": "source.ruby", - "patterns": [ - { - "include": "source.ruby" - } - ], - "end": "(\\\\end\\{minted\\})" - }, - { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{xml\\})", - "captures": { - "1": { - "patterns": [ - { - "include": "#env-mandatory-arg" - } - ] - } - }, - "contentName": "text.xml", - "patterns": [ - { - "include": "text.xml" - } - ], - "end": "(\\\\end\\{minted\\})" - }, - { - "begin": "(\\\\begin\\{minted\\}(?:\\[.*\\])?\\{yaml\\})", - "captures": { - "1": { - "patterns": [ - { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" } ] } @@ -393,7 +431,7 @@ "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" } ] } @@ -405,12 +443,12 @@ ] }, { - "begin": "((?:\\s*)\\\\begin\\{(cppcode(?:\\*)?)\\}(?:\\[.*\\])?)", + "begin": "(\\s*\\\\begin\\{((?:cppcode)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#code-env" + "include": "#begin-env-tokenizer" } ] } @@ -419,20 +457,17 @@ "patterns": [ { "include": "source.cpp.embedded.latex" - }, - { - "include": "source.cpp" } ], "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { - "begin": "((?:\\s*)\\\\begin\\{(hscode(?:\\*)?)\\}(?:\\[.*\\])?)", + "begin": "(\\s*\\\\begin\\{((?:hscode)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#code-env" + "include": "#begin-env-tokenizer" } ] } @@ -446,12 +481,12 @@ "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { - "begin": "((?:\\s*)\\\\begin\\{(luacode(?:\\*)?)\\}(?:\\[.*\\])?)", + "begin": "(\\s*\\\\begin\\{((?:luacode)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#code-env" + "include": "#begin-env-tokenizer" } ] } @@ -465,12 +500,12 @@ "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { - "begin": "((?:\\s*)\\\\begin\\{((?:julia|jl)(?:code|verbatim|block|concode|console|converbatim)(?:\\*)?)\\}(?:\\[.*\\])?)", + "begin": "(\\s*\\\\begin\\{((?:jlcode|jlverbatim|jlblock|jlconcode|jlconsole|jlconverbatim)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#code-env" + "include": "#begin-env-tokenizer" } ] } @@ -484,12 +519,31 @@ "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { - "begin": "((?:\\s*)\\\\begin\\{((?:(?:(?:py|pylab|sympy)(?:code|verbatim|block|concode|console|converbatim))|sageblock|sagesilent|sageverbatim|sageexample|sagecommandline)(?:\\*)?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", + "begin": "(\\s*\\\\begin\\{((?:juliacode|juliaverbatim|juliablock|juliaconcode|juliaconsole|juliaconverbatim)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.julia", + "patterns": [ + { + "include": "source.julia" + } + ], + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" + }, + { + "begin": "(\\s*\\\\begin\\{((?:sageblock|sagesilent|sageverbatim|sageexample|sagecommandline|python|pythonq|pythonrepl)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" } ] } @@ -503,12 +557,69 @@ "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { - "begin": "((?:\\s*)\\\\begin\\{(scalacode(?:\\*)?)\\}(?:\\[.*\\])?)", + "begin": "(\\s*\\\\begin\\{((?:pycode|pyverbatim|pyblock|pyconcode|pyconsole|pyconverbatim)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#code-env" + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.python", + "patterns": [ + { + "include": "source.python" + } + ], + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" + }, + { + "begin": "(\\s*\\\\begin\\{((?:pylabcode|pylabverbatim|pylabblock|pylabconcode|pylabconsole|pylabconverbatim)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.python", + "patterns": [ + { + "include": "source.python" + } + ], + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" + }, + { + "begin": "(\\s*\\\\begin\\{((?:sympycode|sympyverbatim|sympyblock|sympyconcode|sympyconsole|sympyconverbatim)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] + } + }, + "contentName": "source.python", + "patterns": [ + { + "include": "source.python" + } + ], + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" + }, + { + "begin": "(\\s*\\\\begin\\{((?:scalacode)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" } ] } @@ -522,25 +633,12 @@ "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { - "begin": "((?:\\s*)\\\\begin\\{([a-z]*code(?:\\*)?)\\}(?:\\[.*\\])?)", + "begin": "(\\s*\\\\begin\\{((?:asy|asycode)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#code-env" - } - ] - } - }, - "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" - }, - { - "begin": "((?:\\s*)\\\\begin\\{asy\\}(?:\\[.*\\])?)", - "captures": { - "1": { - "patterns": [ - { - "include": "#code-env" + "include": "#begin-env-tokenizer" } ] } @@ -551,15 +649,15 @@ "include": "source.asymptote" } ], - "end": "(\\\\end\\{asy\\}(?:\\s*\\n)?)" + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { - "begin": "((?:\\s*)\\\\begin\\{dot2tex\\}(?:\\[.*\\])?)", + "begin": "(\\s*\\\\begin\\{((?:dot2tex|dotcode)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#code-env" + "include": "#begin-env-tokenizer" } ] } @@ -570,15 +668,15 @@ "include": "source.dot" } ], - "end": "(\\\\end\\{dot2tex\\}(?:\\s*\\n)?)" + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { - "begin": "((?:\\s*)\\\\begin\\{gnuplot\\}(?:\\[.*\\])?)", + "begin": "(\\s*\\\\begin\\{((?:gnuplot)\\*?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", "captures": { "1": { "patterns": [ { - "include": "#code-env" + "include": "#begin-env-tokenizer" } ] } @@ -589,7 +687,20 @@ "include": "source.gnuplot" } ], - "end": "(\\\\end\\{gnuplot\\}(?:\\s*\\n)?)" + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" + }, + { + "begin": "((?:\\s*)\\\\begin\\{([a-z]*code(?:\\*)?)\\}(?:\\[.*\\])?(?:\\{.*\\})?)", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] + } + }, + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)" }, { "begin": "((\\\\)addplot)(?:\\+?)((?:\\[[^\\[]*\\]))*\\s*(gnuplot)\\s*((?:\\[[^\\[]*\\]))*\\s*(\\{)", @@ -639,81 +750,48 @@ "end": "\\s*(\\};)" }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)((?:fboxv|boxedv|V|v|spv)erbatim\\*?)(\\})", + "begin": "(\\s*\\\\begin\\{((?:fboxv|boxedv|V|v|spv)erbatim\\*?)\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, "contentName": "markup.raw.verbatim.latex", - "end": "((\\\\)end)(\\{)(\\4)(\\})", + "end": "(\\\\end\\{\\2\\})", "name": "meta.function.verbatim.latex" }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)(VerbatimOut)(\\})(\\{)([^\\}]*)(\\})", + "begin": "(\\s*\\\\begin\\{VerbatimOut\\}\\{[^\\}]*\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" - }, - "6": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "7": { - "name": "support.class.latex" - }, - "8": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, "contentName": "markup.raw.verbatim.latex", - "end": "((\\\\)end)(\\{)(\\VerbatimOut)(\\})", + "end": "(\\\\end\\{\\VerbatimOut\\})", "name": "meta.function.verbatim.latex" }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)(alltt)(\\})", + "begin": "(\\s*\\\\begin\\{alltt\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, "contentName": "markup.raw.verbatim.latex", - "end": "((\\\\)end)(\\{)(alltt)(\\})", + "end": "(\\\\end\\{alltt\\})", "name": "meta.function.alltt.latex", "patterns": [ { @@ -728,26 +806,18 @@ ] }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)((?:C|c)omment)(\\})", + "begin": "(\\s*\\\\begin\\{([Cc]omment)\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, "contentName": "punctuation.definition.comment.latex", - "end": "((\\\\)end)(\\{)(\\4)(\\})", + "end": "(\\\\end\\{\\2\\})", "name": "meta.function.verbatim.latex" }, { @@ -772,50 +842,34 @@ "name": "meta.function.link.url.latex" }, { - "captures": { - "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" - } - }, "comment": "These two patterns match the \\begin{document} and \\end{document} commands, so that the environment matching pattern following them will ignore those commands.", - "match": "(?:\\s*)((\\\\)begin)(\\{)(document)(\\})", - "name": "meta.function.begin-document.latex" - }, - { + "match": "(\\s*\\\\begin\\{document\\})", + "name": "meta.function.begin-document.latex", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } - }, - "match": "(?:\\s*)((\\\\)end)(\\{)(document)(\\})", - "name": "meta.function.end-document.latex" + } }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)((?:array|equation|(?:IEEE)?eqnarray|multline|align|aligned|alignat|alignedat|flalign|flaligned|flalignat|split|gather|gathered|cases|(?:display)?math|[a-zA-Z]*matrix|(?:(?:arg)?(?:mini|maxi)))(?:\\*|!)?)(\\})(\\s*\\n)?", + "match": "(\\s*\\\\end\\{document\\})", + "name": "meta.function.end-document.latex", + "captures": { + "1": { + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] + } + } + }, + { + "begin": "(?:\\s*)((\\\\)begin)(\\{)((?:array|equation|(?:IEEE)?eqnarray|multline|align|aligned|alignat|alignedat|flalign|flaligned|flalignat|split|gather|gathered|cases|(?:display)?math|[a-zA-Z]*matrix|[pbBvV]?NiceMatrix|[pbBvV]?NiceArray|(?:(?:arg)?(?:mini|maxi)))(?:\\*|!)?)(\\})(\\s*\\n)?", "captures": { "1": { "name": "support.function.be.latex" @@ -862,7 +916,7 @@ "1": { "patterns": [ { - "include": "#env-mandatory-arg" + "include": "#begin-env-tokenizer" } ] } @@ -891,26 +945,18 @@ ] }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)(tabular[xy*]?|xltabular|longtable|(?:long)?tabu|(?:long|tall)?tblr|NiceTabular[X*]?)(\\})(\\s*\\n)?", + "begin": "(\\s*\\\\begin\\{(tabular[xy*]?|xltabular|longtable|(?:long)?tabu|(?:long|tall)?tblr|NiceTabular[X*]?)\\}(\\s*\\n)?)", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, "contentName": "meta.data.environment.tabular.latex", - "end": "(?:\\s*)((\\\\)end)(\\{)(\\4)(\\})(?:\\s*\\n)?", + "end": "(\\s*\\\\end\\{(\\2)\\}(?:\\s*\\n)?)", "name": "meta.function.environment.tabular.latex", "patterns": [ { @@ -927,25 +973,17 @@ ] }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)(itemize|enumerate|description|list)(\\})", + "begin": "(\\s*\\\\begin\\{(itemize|enumerate|description|list)\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, - "end": "((\\\\)end)(\\{)(\\4)(\\})(?:\\s*\\n)?", + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)", "name": "meta.function.environment.list.latex", "patterns": [ { @@ -954,25 +992,17 @@ ] }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)(tikzpicture)(\\})", + "begin": "(\\s*\\\\begin\\{tikzpicture\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, - "end": "((\\\\)end)(\\{)(tikzpicture)(\\})(?:\\s*\\n)?", + "end": "(\\\\end\\{tikzpicture\\}(?:\\s*\\n)?)", "name": "meta.function.environment.latex.tikz", "patterns": [ { @@ -981,25 +1011,17 @@ ] }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)(frame)(\\})", + "begin": "(\\s*\\\\begin\\{frame\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, - "end": "((\\\\)end)(\\{)(frame)(\\})", + "end": "(\\\\end\\{frame\\})", "name": "meta.function.environment.frame.latex", "patterns": [ { @@ -1008,47 +1030,31 @@ ] }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)(mpost[*]?)(\\})", + "begin": "(\\s*\\\\begin\\{(mpost\\*?)\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, - "end": "((\\\\)end)(\\{)(\\4)(\\})(?:\\s*\\n)?", + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)", "name": "meta.function.environment.latex.mpost" }, { - "begin": "(?:\\s*)?((\\\\)begin(\\{)(markdown)\\})", + "begin": "(\\s*\\\\begin\\{markdown\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, - "end": "((\\\\)end)(\\{)(markdown)(\\})", + "end": "(\\\\end\\{markdown\\})", "contentName": "meta.embedded.markdown_latex_combined", "patterns": [ { @@ -1057,25 +1063,17 @@ ] }, { - "begin": "(?:\\s*)((\\\\)begin)(\\{)(\\w+[*]?)(\\})", + "begin": "(\\s*\\\\begin\\{(\\w+\\*?)\\})", "captures": { "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" + "patterns": [ + { + "include": "#begin-env-tokenizer" + } + ] } }, - "end": "((\\\\)end)(\\{)(\\4)(\\})(?:\\s*\\n)?", + "end": "(\\\\end\\{\\2\\}(?:\\s*\\n)?)", "name": "meta.function.environment.general.latex", "patterns": [ { @@ -1396,7 +1394,7 @@ ] }, { - "begin": "((\\\\)(?:\\w*[r|R]ef\\*?))(\\{)", + "begin": "((\\\\)(?:\\w*[rR]ef\\*?))(\\{)", "beginCaptures": { "1": { "name": "keyword.control.ref.latex" @@ -1603,7 +1601,7 @@ "name": "punctuation.definition.verb.latex" } }, - "match": "((\\\\)(?:py|pycon|pylab|pylabcon|sympy|sympycon)[cv]?)((?:\\[[^\\[]*?\\])?)(?:(?:([^a-zA-Z\\{])(.*?)(\\4))|(?:(\\{)(.*?)(\\})))", + "match": "((\\\\)(?:(?:py|pycon|pylab|pylabcon|sympy|sympycon)[cv]?|pyq|pycq|pyif))((?:\\[[^\\[]*?\\])?)(?:(?:([^a-zA-Z\\{])(.*?)(\\4))|(?:(\\{)(.*?)(\\})))", "name": "meta.function.verb.latex" }, { @@ -1839,7 +1837,7 @@ } ] }, - "env-mandatory-arg": { + "begin-env-tokenizer": { "captures": { "1": { "name": "support.function.be.latex" @@ -1879,33 +1877,7 @@ "name": "punctuation.definition.arguments.end.latex" } }, - "match": "((\\\\)(?:begin|end))(\\{)([a-z]*)(\\})(?:(\\[)(.*)(\\]))?(?:(\\{)([^{}]*)(\\}))?" - }, - "code-env": { - "captures": { - "1": { - "name": "support.function.be.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "name": "variable.parameter.function.latex" - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" - }, - "6": { - "name": "punctuation.definition.arguments.optional.begin.latex" - }, - "7": { - "name": "punctuation.definition.arguments.optional.end.latex" - } - }, - "match": "(?:\\s*)((\\\\)(?:begin|end))(\\{)([a-z]+(?:\\*)?)(\\})(?:(\\[).*(\\]))?" + "match": "\\s*((\\\\)(?:begin|end))(\\{)([a-zA-Z]*\\*?)(\\})(?:(\\[)(.*)(\\]))?(?:(\\{)([^{}]*)(\\}))?" }, "definition-label": { "begin": "((\\\\)label)((?:\\[[^\\[]*?\\])*)(\\{)", diff --git a/extensions/latex/syntaxes/TeX.tmLanguage.json b/extensions/latex/syntaxes/TeX.tmLanguage.json index ff494480295..4e3e4d697b5 100644 --- a/extensions/latex/syntaxes/TeX.tmLanguage.json +++ b/extensions/latex/syntaxes/TeX.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/jlelong/vscode-latex-basics/commit/b98c2d4911652824fc990f4b26c9c30be59b78a2", + "version": "https://github.com/jlelong/vscode-latex-basics/commit/8776a0856846b63d9e5765e8ec42a8a2f4f52219", "name": "TeX", "scopeName": "text.tex", "patterns": [ @@ -167,7 +167,7 @@ "name": "punctuation.math.bracket.pair.tex" }, { - "match": "\\\\(left|right|((big|bigg|Big|Bigg)[lr]?))([\\(\\[\\<\\>\\]\\)\\.\\|]|\\\\[{}|]|\\\\[lr]?[Vv]ert|\\\\[lr]angle|\\\\\\|)", + "match": "\\\\(left|right|((big|bigg|Big|Bigg)[lr]?))([\\(\\[\\<\\>\\]\\)\\.\\|]|\\\\[{}|]|\\\\[lr]?[Vv]ert|\\\\[lr]angle)", "name": "punctuation.math.bracket.pair.big.tex" }, { diff --git a/extensions/latex/syntaxes/cpp-grammar-bailout.tmLanguage.json b/extensions/latex/syntaxes/cpp-grammar-bailout.tmLanguage.json index bf084fd2fd2..a303594f0ae 100644 --- a/extensions/latex/syntaxes/cpp-grammar-bailout.tmLanguage.json +++ b/extensions/latex/syntaxes/cpp-grammar-bailout.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/jlelong/vscode-latex-basics/commit/db888fc191f6b5610cd6866cc49017fc3dfb00b5", + "version": "https://github.com/jlelong/vscode-latex-basics/commit/ffe263692d6096b24e4897650e933c587fa9c55f", "name": "C++", "scopeName": "source.cpp.embedded.latex", "patterns": [ @@ -573,7 +573,7 @@ "name": "comment.block.cpp" }, "builtin_storage_type_initilizer": { - "begin": "(?:\\s)*+(?(?:\\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)))((?:(?:(?:constexpr)|(?:consteval)|(?: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)))((?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "0": { @@ -1804,7 +1801,7 @@ ] }, "constructor_root": { - "begin": "\\s*+((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "\\s*+((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "0": { @@ -2179,7 +2176,7 @@ ] }, "control_flow_keywords": { - "match": "((?:((?:(?>(?:\\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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", "end": "\\}|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "1": { @@ -3126,14 +3123,11 @@ "patterns": [ { "include": "#evaluation_context" - }, - { - "include": "#c_conditional_context" } ] }, "destructor_inline": { - "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)))((?:(?:(?:constexpr)|(?:explicit)|(?:mutable)|(?:virtual)|(?:inline)|(?:friend))((?:(?:(?:(?>(?:\\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)|(?:consteval)|(?:explicit)|(?:mutable)|(?:virtual)|(?:inline)|(?:friend))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(~(?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "0": { @@ -3369,7 +3363,7 @@ ] }, "destructor_root": { - "begin": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "0": { @@ -3661,7 +3655,7 @@ }, "diagnostic": { "begin": "(^((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(#)(?:(?:\\s)+)?((?:error|warning)))\\b(?:(?:\\s)+)?", - "end": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?|\\?\\?>)(?:(?:\\s)+)?(;)|(;))|(?=[;>\\[\\]=]))|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "0": { @@ -4525,7 +4519,7 @@ ] }, "function_call": { - "begin": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\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<11>?)+>)(?:\\s)*+)?(\\()", + "begin": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\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<11>?)+>)(?:\\s)*+)?(\\()", "end": "\\)|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "1": { @@ -4599,7 +4593,7 @@ ] }, "function_definition": { - "begin": "(?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<60>?)+>)?(?![\\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)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\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)))(?=\\()", + "begin": "(?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)?(?![\\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)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\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)))(?=\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "0": { @@ -4671,7 +4665,7 @@ "11": { "patterns": [ { - "match": "((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))", + "match": "((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))", "captures": { "1": { "name": "storage.modifier.$1.cpp" @@ -5162,7 +5156,7 @@ ] }, { - "match": "(?<=^|\\))(?:(?:\\s)+)?(->)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<23>?)+>)?(?![\\w<:.]))", + "match": "(?<=^|\\))(?:(?:\\s)+)?(->)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "punctuation.definition.function.return-type.cpp" @@ -5410,7 +5404,7 @@ ] }, "function_pointer": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "1": { @@ -5761,7 +5755,7 @@ ] }, "function_pointer_parameter": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "1": { @@ -6112,7 +6106,7 @@ ] }, "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}))*)", + "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": { + "2": { "patterns": [ { "match": "(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))", @@ -6219,7 +6210,44 @@ } ] }, + "3": { + "name": "keyword.control.goto.cpp" + }, "4": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "5": { + "patterns": [ + { + "match": "(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))", + "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" + } + ] + } + } + } + ] + }, + "6": { "name": "entity.name.label.call.cpp" } } @@ -6482,7 +6510,7 @@ "name": "storage.type.modifier.virtual.cpp" }, { - "match": "(?<=protected|virtual|private|public|,|:)(?:(?:\\s)+)?(?!(?:(?:(?:protected)|(?:private)|(?:public))|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<12>?)+>)?(?![\\w<:.]))", + "match": "(?<=protected|virtual|private|public|,|:)(?:(?:\\s)+)?(?!(?:(?:(?:protected)|(?:private)|(?:public))|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -6680,7 +6708,7 @@ ] }, "inline_builtin_storage_type": { - "match": "(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(#)(?:(?:\\s)+)?line\\b", - "end": "(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(#)(?:(?:\\s)+)?define\\b)(?:(?:\\s)+)?((?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?\\*|->)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:(?:\\s)+)?(?:(?:\\.\\*|\\.)|(?:->\\*|->))(?:(?:\\s)+)?)*)(?:(?:\\s)+)?(\\b(?!uint_least32_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint_least16_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint_least64_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int_least32_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int_least64_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint_fast32_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint_fast64_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint_least8_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint_fast16_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int_least16_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int_fast16_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int_least8_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint_fast8_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int_fast64_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int_fast32_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int_fast8_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|suseconds_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|useconds_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|in_addr_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uintmax_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uintmax_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uintmax_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|in_port_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uintptr_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|blksize_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint32_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint64_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|u_quad_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|intmax_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|intmax_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|unsigned[^Pattern.new(\n match: \\/\\w\\/,\n)]|blkcnt_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint16_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|intptr_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|swblk_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|wchar_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|u_short[^Pattern.new(\n match: \\/\\w\\/,\n)]|qaddr_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|caddr_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|daddr_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|fixpt_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|nlink_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|segsz_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|clock_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|ssize_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int16_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int32_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int64_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint8_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int8_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|mode_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|quad_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|ushort[^Pattern.new(\n match: \\/\\w\\/,\n)]|u_long[^Pattern.new(\n match: \\/\\w\\/,\n)]|u_char[^Pattern.new(\n match: \\/\\w\\/,\n)]|double[^Pattern.new(\n match: \\/\\w\\/,\n)]|signed[^Pattern.new(\n match: \\/\\w\\/,\n)]|time_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|size_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|key_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|div_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|ino_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uid_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|gid_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|off_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|pid_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|float[^Pattern.new(\n match: \\/\\w\\/,\n)]|dev_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|u_int[^Pattern.new(\n match: \\/\\w\\/,\n)]|short[^Pattern.new(\n match: \\/\\w\\/,\n)]|bool[^Pattern.new(\n match: \\/\\w\\/,\n)]|id_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|uint[^Pattern.new(\n match: \\/\\w\\/,\n)]|long[^Pattern.new(\n match: \\/\\w\\/,\n)]|char[^Pattern.new(\n match: \\/\\w\\/,\n)]|void[^Pattern.new(\n match: \\/\\w\\/,\n)]|auto[^Pattern.new(\n match: \\/\\w\\/,\n)]|id_t[^Pattern.new(\n match: \\/\\w\\/,\n)]|int[^Pattern.new(\n match: \\/\\w\\/,\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}))*\\b(?!\\())", + "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_least16_t[^\\w]|uint_least32_t[^\\w]|uint_least64_t[^\\w]|int_least16_t[^\\w]|int_least32_t[^\\w]|int_least64_t[^\\w]|uint_least8_t[^\\w]|uint_fast16_t[^\\w]|uint_fast32_t[^\\w]|uint_fast64_t[^\\w]|int_least8_t[^\\w]|int_fast16_t[^\\w]|int_fast32_t[^\\w]|int_fast64_t[^\\w]|uint_fast8_t[^\\w]|suseconds_t[^\\w]|int_fast8_t[^\\w]|useconds_t[^\\w]|blksize_t[^\\w]|in_addr_t[^\\w]|in_port_t[^\\w]|uintptr_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|unsigned[^\\w]|u_quad_t[^\\w]|blkcnt_t[^\\w]|uint16_t[^\\w]|uint32_t[^\\w]|uint64_t[^\\w]|intptr_t[^\\w]|intmax_t[^\\w]|intmax_t[^\\w]|wchar_t[^\\w]|u_short[^\\w]|qaddr_t[^\\w]|caddr_t[^\\w]|daddr_t[^\\w]|fixpt_t[^\\w]|nlink_t[^\\w]|segsz_t[^\\w]|swblk_t[^\\w]|clock_t[^\\w]|ssize_t[^\\w]|int16_t[^\\w]|int32_t[^\\w]|int64_t[^\\w]|uint8_t[^\\w]|signed[^\\w]|double[^\\w]|u_char[^\\w]|u_long[^\\w]|ushort[^\\w]|quad_t[^\\w]|mode_t[^\\w]|size_t[^\\w]|time_t[^\\w]|int8_t[^\\w]|short[^\\w]|float[^\\w]|u_int[^\\w]|div_t[^\\w]|dev_t[^\\w]|gid_t[^\\w]|ino_t[^\\w]|key_t[^\\w]|pid_t[^\\w]|off_t[^\\w]|uid_t[^\\w]|auto[^\\w]|void[^\\w]|char[^\\w]|long[^\\w]|bool[^\\w]|uint[^\\w]|id_t[^\\w]|id_t[^\\w]|int[^\\w])(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b(?!\\())", "captures": { "1": { "patterns": [ @@ -7474,7 +7503,7 @@ ] }, "misc_keywords": { - "match": "((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<8>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<8>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<55>?)+>)?(?![\\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)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\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)))(?=\\<|\\()", + "begin": "(?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)?(?![\\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)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\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)))(?=\\<|\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "0": { @@ -9062,14 +9091,14 @@ }, { "match": "&|\\||\\^|~", - "name": "keyword.operator.cpp" + "name": "keyword.operator.bitwise.cpp" }, { "include": "#assignment_operator" }, { "match": "%|\\*|\\/|-|\\+", - "name": "keyword.operator.cpp" + "name": "keyword.operator.arithmetic.cpp" }, { "include": "#ternary_operator" @@ -9079,7 +9108,7 @@ "over_qualified_types": { "patterns": [ { - "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)", + "match": "(\\bstruct)((?:((?:(?>(?:\\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" @@ -9408,7 +9437,7 @@ } }, { - "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)", + "match": "(\\benum)((?:((?:(?>(?:\\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" @@ -9737,7 +9766,7 @@ } }, { - "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)", + "match": "(\\bunion)((?:((?:(?>(?:\\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" @@ -10066,7 +10095,7 @@ } }, { - "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)", + "match": "(\\bclass)((?:((?:(?>(?:\\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" @@ -10446,7 +10475,7 @@ "include": "#vararg_ellipses" }, { - "match": "((?:((?:(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -10768,7 +10797,7 @@ ] }, "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)", + "match": "(\\bclass)((?:((?:(?>(?:\\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" @@ -11097,7 +11126,7 @@ } }, "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)", + "match": "(\\benum)((?:((?:(?>(?:\\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" @@ -11484,7 +11513,7 @@ "include": "#vararg_ellipses" }, { - "match": "((?:((?:(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -11808,7 +11837,7 @@ ] }, "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)", + "match": "(\\bstruct)((?:((?:(?>(?:\\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" @@ -12137,7 +12166,7 @@ } }, "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)", + "match": "(\\bunion)((?:((?:(?>(?:\\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" @@ -12494,7 +12523,7 @@ }, "pragma": { "begin": "^((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(#)(?:(?:\\s)+)?pragma\\b", - "end": "(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<11>?)+>)?(?![\\w<:.])", + "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)?(?![\\w<:.])", "captures": { "0": { "patterns": [ @@ -13089,7 +13118,7 @@ } }, "scope_resolution": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13111,7 +13140,7 @@ } }, "scope_resolution_function_call": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13133,7 +13162,7 @@ } }, "scope_resolution_function_call_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13171,7 +13200,7 @@ } }, "scope_resolution_function_definition": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13193,7 +13222,7 @@ } }, "scope_resolution_function_definition_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13231,7 +13260,7 @@ } }, "scope_resolution_function_definition_operator_overload": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13253,7 +13282,7 @@ } }, "scope_resolution_function_definition_operator_overload_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13291,7 +13320,7 @@ } }, "scope_resolution_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13329,7 +13358,7 @@ } }, "scope_resolution_namespace_alias": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13351,7 +13380,7 @@ } }, "scope_resolution_namespace_alias_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13389,7 +13418,7 @@ } }, "scope_resolution_namespace_block": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13411,7 +13440,7 @@ } }, "scope_resolution_namespace_block_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13449,7 +13478,7 @@ } }, "scope_resolution_namespace_using": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13471,7 +13500,7 @@ } }, "scope_resolution_namespace_using_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13509,7 +13538,7 @@ } }, "scope_resolution_parameter": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13531,7 +13560,7 @@ } }, "scope_resolution_parameter_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13569,7 +13598,7 @@ } }, "scope_resolution_template_call": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13591,7 +13620,7 @@ } }, "scope_resolution_template_call_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13629,7 +13658,7 @@ } }, "scope_resolution_template_definition": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13651,7 +13680,7 @@ } }, "scope_resolution_template_definition_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13693,7 +13722,7 @@ "name": "punctuation.terminator.statement.cpp" }, "simple_type": { - "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<12>?)+>)?(?![\\w<:.]))(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?", + "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -15207,7 +15236,7 @@ } }, "storage_specifiers": { - "match": "((?:((?:(?>(?:\\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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<29>?)+>)?(?![\\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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<29>?)+>)?(?![\\w<:.]))|(.*(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)?(?:(?:\\s)+)?(?:(;)|\\n)", + "match": "(using)(?:(?:\\s)+)?(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)?(?![\\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))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)?(?![\\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" @@ -17593,7 +17616,7 @@ "endCaptures": {}, "patterns": [ { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<18>?)+>)?(?![\\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)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()|(?=\\\\end\\{(?:minted|cppcode)\\})", "beginCaptures": { "1": { @@ -18878,7 +18901,7 @@ ] }, "typename": { - "match": "(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|synchronized|dynamic_cast|thread_local|static_cast|const_cast|co_return|constexpr|constexpr|constexpr|co_return|protected|namespace|consteval|noexcept|decltype|template|operator|noexcept|co_yield|co_await|reflexpr|continue|co_await|co_yield|requires|volatile|register|restrict|explicit|volatile|noexcept|typename|default|_Pragma|mutable|include|concept|alignas|virtual|alignof|__asm__|defined|mutable|typedef|warning|private|and_eq|define|pragma|typeid|switch|bitand|return|ifndef|export|struct|sizeof|module|static|public|extern|inline|friend|delete|xor_eq|import|not_eq|class|compl|bitor|throw|or_eq|while|catch|break|union|const|const|endif|ifdef|undef|error|using|else|line|goto|else|elif|this|enum|case|new|asm|not|try|for|and|xor|or|if|do|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:atomic_cancel)|(?:__has_include)|(?:dynamic_cast)|(?:synchronized)|(?:thread_local)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:consteval)|(?:co_return)|(?:co_return)|(?:constexpr)|(?:protected)|(?:constexpr)|(?:namespace)|(?:noexcept)|(?:typename)|(?:decltype)|(?:template)|(?:operator)|(?:noexcept)|(?:co_yield)|(?:co_await)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:reflexpr)|(?:noexcept)|(?:requires)|(?:alignas)|(?:typedef)|(?:nullptr)|(?:alignof)|(?:mutable)|(?:concept)|(?:virtual)|(?:defined)|(?:__asm__)|(?:include)|(?:_Pragma)|(?:mutable)|(?:default)|(?:warning)|(?:private)|(?:module)|(?:return)|(?:not_eq)|(?:xor_eq)|(?:and_eq)|(?:ifndef)|(?:pragma)|(?:export)|(?:import)|(?:sizeof)|(?:static)|(?:delete)|(?:public)|(?:define)|(?:extern)|(?:inline)|(?:typeid)|(?:switch)|(?:friend)|(?:bitand)|(?:false)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:const)|(?: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<17>?)+>)?(?![\\w<:.]))", + "match": "(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?: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}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "storage.modifier.cpp" @@ -19767,7 +19790,7 @@ } }, "using_namespace": { - "begin": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?[^\\[\\]\\\\]|\\\\.|\\[\\g*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n ((?>[^\\s()]+)|\\(\\g*\\))*)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in double quotes…\n | ((').+?(')) # or in single quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n", + "match": "(?x)\n (\\[)((?[^\\[\\]\\\\]|\\\\.|\\[\\g*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n # The url\n [ \\t]*\n (\n (<)([^<>\\n]*)(>)\n | ((?(?>[^\\s()]+)|\\(\\g*\\))*)\n )\n [ \\t]*\n # The title \n (?:\n ((\\()[^()]*(\\))) # Match title in parens…\n | ((\")[^\"]*(\")) # or in double quotes…\n | ((')[^']*(')) # or in single quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n", "name": "meta.link.inline.markdown" }, "link-ref": { @@ -2808,7 +2847,7 @@ "name": "punctuation.definition.constant.end.markdown" } }, - "match": "(\\[)((?[^\\[\\]\\\\]|\\\\.|\\[\\g*+\\])*+)(\\])(\\[)([^\\]]*+)(\\])", + "match": "(?[^\\[\\]\\\\]|\\\\.|\\[\\g*+\\])*+)(\\])(\\[)([^\\]]*+)(\\])", "name": "meta.link.reference.markdown" }, "link-ref-literal": { @@ -2829,7 +2868,7 @@ "name": "punctuation.definition.constant.end.markdown" } }, - "match": "(\\[)((?[^\\[\\]\\\\]|\\\\.|\\[\\g*+\\])*+)(\\])[ ]?(\\[)(\\])", + "match": "(?[^\\[\\]\\\\]|\\\\.|\\[\\g*+\\])*+)(\\])[ ]?(\\[)(\\])", "name": "meta.link.reference.literal.markdown" }, "link-ref-shortcut": { @@ -2844,7 +2883,7 @@ "name": "punctuation.definition.link.title.end.markdown" } }, - "match": "(\\[)(\\S+?)(\\])", + "match": "(? = (ctx) => { code { font-size: 1em; + font-family: var(--vscode-editor-font-family); } pre code { - font-family: var(--vscode-editor-font-family); - line-height: 1.357em; white-space: pre-wrap; } diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 0ce010f6cc3..9eac5d01bbb 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -6,7 +6,7 @@ "icon": "icon.png", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.20.0" }, @@ -16,7 +16,6 @@ "Programming Languages" ], "enabledApiProposals": [ - "textEditorDrop", "documentPaste" ], "activationEvents": [ @@ -188,22 +187,22 @@ }, { "command": "markdown.showSource", - "when": "markdownPreviewFocus", + "when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'", "group": "navigation" }, { "command": "markdown.preview.refresh", - "when": "markdownPreviewFocus", + "when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'", "group": "1_markdown" }, { "command": "markdown.preview.toggleLock", - "when": "markdownPreviewFocus", + "when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'", "group": "1_markdown" }, { "command": "markdown.showPreviewSecuritySelector", - "when": "markdownPreviewFocus", + "when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'", "group": "1_markdown" } ], @@ -248,7 +247,7 @@ }, { "command": "markdown.showSource", - "when": "markdownPreviewFocus", + "when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'", "group": "navigation" }, { @@ -257,11 +256,11 @@ }, { "command": "markdown.showPreviewSecuritySelector", - "when": "markdownPreviewFocus" + "when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'" }, { "command": "markdown.preview.toggleLock", - "when": "markdownPreviewFocus" + "when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'" }, { "command": "markdown.preview.refresh", @@ -269,7 +268,7 @@ }, { "command": "markdown.preview.refresh", - "when": "markdownPreviewFocus" + "when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'" }, { "command": "markdown.findAllFileReferences", @@ -399,16 +398,27 @@ "description": "%configuration.markdown.suggest.paths.enabled.description%", "scope": "resource" }, - "markdown.trace": { + "markdown.trace.extension": { "type": "string", "enum": [ "off", "verbose" ], "default": "off", - "description": "%markdown.trace.desc%", + "description": "%markdown.trace.extension.desc%", "scope": "window" }, + "markdown.trace.server": { + "type": "string", + "scope": "window", + "enum": [ + "off", + "messages", + "verbose" + ], + "default": "off", + "description": "%markdown.trace.server.desc%" + }, "markdown.editor.drop.enabled": { "type": "boolean", "default": true, @@ -479,6 +489,7 @@ "type": "string", "scope": "resource", "markdownDescription": "%configuration.markdown.experimental.validate.fileLinks.markdownFragmentLinks.description%", + "default": "ignore", "enum": [ "ignore", "warning", @@ -498,13 +509,54 @@ "tags": [ "experimental" ] + }, + "markdown.experimental.updateLinksOnFileMove.enabled": { + "type": "string", + "enum": [ + "prompt", + "always", + "never" + ], + "markdownEnumDescriptions": [ + "%configuration.markdown.experimental.updateLinksOnFileMove.enabled.prompt%", + "%configuration.markdown.experimental.updateLinksOnFileMove.enabled.always%", + "%configuration.markdown.experimental.updateLinksOnFileMove.enabled.never%" + ], + "default": "never", + "markdownDescription": "%configuration.markdown.experimental.updateLinksOnFileMove.enabled%", + "scope": "resource", + "tags": [ + "experimental" + ] + }, + "markdown.experimental.updateLinksOnFileMove.externalFileGlobs": { + "type": "string", + "default": "**/*.{jpg,jpe,jpeg,png,bmp,gif,ico,webp,avif,tiff,svg,mp4}", + "description": "%configuration.markdown.experimental.updateLinksOnFileMove.fileGlobs%", + "scope": "resource", + "tags": [ + "experimental" + ] + }, + "markdown.experimental.updateLinksOnFileMove.enableForDirectories": { + "type": "boolean", + "default": true, + "description": "%configuration.markdown.experimental.updateLinksOnFileMove.enableForDirectories%", + "scope": "resource", + "tags": [ + "experimental" + ] } } }, "configurationDefaults": { "[markdown]": { "editor.wordWrap": "on", - "editor.quickSuggestions": false + "editor.quickSuggestions": { + "comments": "off", + "strings": "off", + "other": "off" + } } }, "jsonValidation": [ @@ -534,8 +586,8 @@ ] }, "scripts": { - "compile": "gulp compile-extension:markdown-language-features && npm run build-preview && npm run build-notebook", - "watch": "npm run build-preview && gulp watch-extension:markdown-language-features", + "compile": "gulp compile-extension:markdown-language-features-languageService && gulp compile-extension:markdown-language-features-server && gulp compile-extension:markdown-language-features && npm run build-preview && npm run build-notebook", + "watch": "npm run build-preview && gulp watch-extension:markdown-language-features watch-extension:markdown-language-features-languageService watch-extension:markdown-language-features-server", "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-notebook": "node ./esbuild-notebook", @@ -544,15 +596,16 @@ "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, "dependencies": { - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "dompurify": "^2.3.3", "highlight.js": "^11.4.0", "markdown-it": "^12.3.2", "markdown-it-front-matter": "^0.2.1", "morphdom": "^2.6.1", "picomatch": "^2.3.1", + "vscode-languageclient": "^8.0.2", "vscode-languageserver-textdocument": "^1.0.4", - "vscode-nls": "^5.0.0", + "vscode-nls": "^5.1.0", "vscode-uri": "^3.0.3" }, "devDependencies": { @@ -562,7 +615,9 @@ "@types/picomatch": "^2.3.0", "@types/vscode-notebook-renderer": "^1.60.0", "@types/vscode-webview": "^1.57.0", - "lodash.throttle": "^4.1.1" + "lodash.throttle": "^4.1.1", + "vscode-languageserver-types": "^3.17.2", + "vscode-markdown-languageservice": "^0.0.0-alpha.10" }, "repository": { "type": "git", diff --git a/extensions/markdown-language-features/package.nls.json b/extensions/markdown-language-features/package.nls.json index 71c9fedc1a3..d4cea703cc2 100644 --- a/extensions/markdown-language-features/package.nls.json +++ b/extensions/markdown-language-features/package.nls.json @@ -17,7 +17,8 @@ "markdown.showSource.title": "Show Source", "markdown.styles.dec": "A list of URLs or local paths to CSS style sheets to use from the Markdown preview. Relative paths are interpreted relative to the folder open in the Explorer. If there is no open folder, they are interpreted relative to the location of the Markdown file. All '\\' need to be written as '\\\\'.", "markdown.showPreviewSecuritySelector.title": "Change Preview Security Settings", - "markdown.trace.desc": "Enable debug logging for the Markdown extension.", + "markdown.trace.extension.desc": "Enable debug logging for the Markdown extension.", + "markdown.trace.server.desc": "Traces the communication between VS Code and the Markdown language server.", "markdown.preview.refresh.title": "Refresh Preview", "markdown.preview.toggleLock.title": "Toggle Preview Locking", "markdown.findAllFileReferences": "Find File References", @@ -28,7 +29,7 @@ "configuration.markdown.links.openLocation.currentGroup": "Open links in the active editor group.", "configuration.markdown.links.openLocation.beside": "Open links beside the active editor.", "configuration.markdown.suggest.paths.enabled.description": "Enable/disable path suggestions for markdown links", - "configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#workbench.experimental.editor.dropIntoEditor.enabled#`.", + "configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#editor.dropIntoEditor.enabled#`.", "configuration.markdown.editor.pasteLinks.enabled": "Enable/disable pasting files into a Markdown editor inserts Markdown links. Requires enabling `#editor.experimental.pasteActions.enabled#`.", "configuration.markdown.experimental.validate.enabled.description": "Enable/disable all error reporting in Markdown files.", "configuration.markdown.experimental.validate.referenceLinks.enabled.description": "Validate reference links in Markdown files, e.g. `[link][ref]`. Requires enabling `#markdown.experimental.validate.enabled#`.", @@ -36,5 +37,11 @@ "configuration.markdown.experimental.validate.fileLinks.enabled.description": "Validate links to other files in Markdown files, e.g. `[link](/path/to/file.md)`. This checks that the target files exists. Requires enabling `#markdown.experimental.validate.enabled#`.", "configuration.markdown.experimental.validate.fileLinks.markdownFragmentLinks.description": "Validate the fragment part of links to headers in other files in Markdown files, e.g. `[link](/path/to/file.md#header)`. Inherits the setting value from `#markdown.experimental.validate.fragmentLinks.enabled#` by default.", "configuration.markdown.experimental.validate.ignoreLinks.description": "Configure links that should not be validated. For example `/about` would not validate the link `[about](/about)`, while the glob `/assets/**/*.svg` would let you skip validation for any link to `.svg` files under the `assets` directory.", + "configuration.markdown.experimental.updateLinksOnFileMove.enabled": "Try to update links in Markdown files when a file is renamed/moved in the workspace. Use `#markdown.experimental.updateLinksOnFileMove.externalFileGlobs#` to configure which files trigger link updates.", + "configuration.markdown.experimental.updateLinksOnFileMove.enabled.prompt": "Prompt on each file move.", + "configuration.markdown.experimental.updateLinksOnFileMove.enabled.always": "Always update links automatically.", + "configuration.markdown.experimental.updateLinksOnFileMove.enabled.never": "Never try to update link and don't prompt.", + "configuration.markdown.experimental.updateLinksOnFileMove.fileGlobs": "A glob that specifies which files besides markdown should trigger a link update.", + "configuration.markdown.experimental.updateLinksOnFileMove.enableForDirectories": "enable/disable updating links when a directory is moved or renamed in the workspace.", "workspaceTrust": "Required for loading styles configured in the workspace." } diff --git a/extensions/markdown-language-features/server/.npmignore b/extensions/markdown-language-features/server/.npmignore new file mode 100644 index 00000000000..bfd4215998c --- /dev/null +++ b/extensions/markdown-language-features/server/.npmignore @@ -0,0 +1,12 @@ +.vscode/ +.github/ +out/test/ +src/ +.eslintrc.js +.gitignore +tsconfig*.json +*.tsbuildinfo +*.map +example.cjs +CODE_OF_CONDUCT.md +SECURITY.md \ No newline at end of file diff --git a/extensions/markdown-language-features/server/.vscode/launch.json b/extensions/markdown-language-features/server/.vscode/launch.json new file mode 100644 index 00000000000..fd9033bffaa --- /dev/null +++ b/extensions/markdown-language-features/server/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "0.1.0", + // List of configurations. Add new configurations or edit existing ones. + "configurations": [ + { + "name": "Attach", + "type": "node", + "request": "attach", + "port": 7997, + "sourceMaps": true, + "outFiles": [ + "${workspaceFolder}/out/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/extensions/markdown-language-features/server/.vscode/settings.json b/extensions/markdown-language-features/server/.vscode/settings.json new file mode 100644 index 00000000000..7a73a41bfdf --- /dev/null +++ b/extensions/markdown-language-features/server/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/extensions/markdown-language-features/server/.vscode/tasks.json b/extensions/markdown-language-features/server/.vscode/tasks.json new file mode 100644 index 00000000000..ecc951a7baf --- /dev/null +++ b/extensions/markdown-language-features/server/.vscode/tasks.json @@ -0,0 +1,27 @@ +{ + "version": "2.0.0", + "command": "npm", + "args": [ + "run", + "watch" + ], + "isBackground": true, + "problemMatcher": "$tsc-watch", + "tasks": [ + { + "label": "npm", + "type": "shell", + "command": "npm", + "args": [ + "run", + "watch" + ], + "isBackground": true, + "problemMatcher": "$tsc-watch", + "group": { + "_id": "build", + "isDefault": false + } + } + ] +} \ No newline at end of file diff --git a/extensions/markdown-language-features/server/README.md b/extensions/markdown-language-features/server/README.md new file mode 100644 index 00000000000..49670fc800d --- /dev/null +++ b/extensions/markdown-language-features/server/README.md @@ -0,0 +1,128 @@ +# Markdown Language Server + +> **❗ Import** This is still in development. While the language server is being used by VS Code, it has not yet been tested with other clients. + +The Markdown language server powers VS Code's built-in markdown support, providing tools for writing and browsing Markdown files. It runs as a separate executable and implements the [language server protocol](https://microsoft.github.io/language-server-protocol/overview). + +This server uses the [Markdown Language Service](https://github.com/microsoft/vscode-markdown-languageservice) to implement almost all of the language features. You can use that library if you need a library for working with Markdown instead of a full language server. + + +## Server capabilities + +- [Completions](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion) for Markdown links. + +- [Folding](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange) of Markdown regions, block elements, and header sections. + +- [Smart selection](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_selectionRange) for inline elements, block elements, and header sections. + +- [Document Symbols](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) for quick navigation to headers in a document. + +- [Workspace Symbols](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_symbol) for quick navigation to headers in the workspace + +- [Document links](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentLink) for making Markdown links in a document clickable. + +- [Find all references](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references) to headers and links across all Markdown files in the workspace. + +- [Go to definition](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition) from links to headers or link definitions. + +- [Rename](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rename) of headers and links across all Markdown files in the workspace. + +- Find all references to a file. Uses a custom `markdown/getReferencesToFileInWorkspace` message. + +- [Code Actions](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeAction) + + - Organize link definitions source action. + - Extract link to definition refactoring. + +- (experimental) Updating links when a file is moved / renamed. Uses a custom `markdown/getEditForFileRenames` message. + +- (experimental) [Pull diagnostics (validation)](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_pullDiagnostics) for links. + + +## Client requirements + +### Initialization options + +The client can send the following initialization options to the server: + +- `markdownFileExtensions` Array file extensions that should be considered as Markdown. These should not include the leading `.`. For example: `['md', 'mdown', 'markdown']`. + +### Settings + +Clients may send a `workspace/didChangeConfiguration` notification to notify the server of settings changes. +The server supports the following settings: + +- `markdown` + - `suggest` + - `paths` + - `enabled` — Enable/disable path suggestions. + - `experimental` + - `validate` + - `enabled` — Enable/disable all validation. + - `referenceLinks` + - `enabled` — Enable/disable validation of reference links: `[text][ref]` + - `fragmentLinks` + - `enabled` — Enable/disable validation of links to fragments in the current files: `[text](#head)` + - `fileLinks` + - `enabled` — Enable/disable validation of links to file in the workspace. + - `markdownFragmentLinks` — Enable/disable validation of links to headers in other Markdown files. + - `ignoreLinks` — Array of glob patterns for files that should not be validated. + +### Custom requests + +To support all of the features of the language server, the client needs to implement a few custom request types. The definitions of these request types can be found in [`protocol.ts`](./src/protocol.ts) + +#### `markdown/parse` + +Get the tokens for a Markdown file. Clients are expected to use [Markdown-it](https://github.com/markdown-it/markdown-it) for this. + +We require that clients bring their own version of Markdown-it so that they can customize/extend Markdown-it. + +#### `markdown/fs/readFile` + +Read the contents of a file in the workspace. + +#### `markdown/fs/readDirectory` + +Read the contents of a directory in the workspace. + +#### `markdown/fs/stat` + +Check if a given file/directory exists in the workspace. + +#### `markdown/fs/watcher/create` + +Create a file watcher. This is needed for diagnostics support. + +#### `markdown/fs/watcher/delete` + +Delete a previously created file watcher. + +#### `markdown/findMarkdownFilesInWorkspace` + +Get a list of all markdown files in the workspace. + + +## Contribute + +The source code of the Markdown language server can be found in the [VSCode repository](https://github.com/microsoft/vscode) at [extensions/markdown-language-features/server](https://github.com/microsoft/vscode/tree/master/extensions/markdown-language-features/server). + +File issues and pull requests in the [VSCode GitHub Issues](https://github.com/microsoft/vscode/issues). See the document [How to Contribute](https://github.com/microsoft/vscode/wiki/How-to-Contribute) on how to build and run from source. + +Most of the functionality of the server is located in libraries: + +- [vscode-markdown-languageservice](https://github.com/microsoft/vscode-markdown-languageservice) contains the implementation of all features as a reusable library. +- [vscode-languageserver-node](https://github.com/microsoft/vscode-languageserver-node) contains the implementation of language server for NodeJS. + +Help on any of these projects is very welcome. + +## Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the [MIT](https://github.com/microsoft/vscode/blob/master/LICENSE.txt) License. + diff --git a/extensions/markdown-language-features/server/extension-browser.webpack.config.js b/extensions/markdown-language-features/server/extension-browser.webpack.config.js new file mode 100644 index 00000000000..b36d36f936d --- /dev/null +++ b/extensions/markdown-language-features/server/extension-browser.webpack.config.js @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withBrowserDefaults = require('../../shared.webpack.config').browser; +const path = require('path'); + +module.exports = withBrowserDefaults({ + context: __dirname, + entry: { + extension: './src/browser/main.ts', + }, + output: { + filename: 'main.js', + path: path.join(__dirname, 'dist', 'browser'), + libraryTarget: 'var', + library: 'serverExportVar' + } +}); diff --git a/extensions/markdown-language-features/server/extension.webpack.config.js b/extensions/markdown-language-features/server/extension.webpack.config.js new file mode 100644 index 00000000000..a1917b54dc6 --- /dev/null +++ b/extensions/markdown-language-features/server/extension.webpack.config.js @@ -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. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withDefaults = require('../../shared.webpack.config'); +const path = require('path'); + +module.exports = withDefaults({ + context: path.join(__dirname), + entry: { + extension: './src/node/main.ts', + }, + output: { + filename: 'main.js', + path: path.join(__dirname, 'dist', 'node'), + } +}); diff --git a/extensions/markdown-language-features/server/package.json b/extensions/markdown-language-features/server/package.json new file mode 100644 index 00000000000..a027b548215 --- /dev/null +++ b/extensions/markdown-language-features/server/package.json @@ -0,0 +1,27 @@ +{ + "name": "vscode-markdown-languageserver", + "description": "Markdown language server", + "version": "0.0.0-alpha-3", + "author": "Microsoft Corporation", + "license": "MIT", + "engines": { + "node": "*" + }, + "main": "./out/node/main", + "browser": "./dist/browser/main", + "dependencies": { + "vscode-languageserver": "^8.0.2", + "vscode-languageserver-textdocument": "^1.0.5", + "vscode-languageserver-types": "^3.17.1", + "vscode-markdown-languageservice": "^0.1.0-alpha.2", + "vscode-nls": "^5.0.1", + "vscode-uri": "^3.0.3" + }, + "devDependencies": { + "@types/node": "16.x" + }, + "scripts": { + "compile": "gulp compile-extension:markdown-language-features-server", + "watch": "gulp watch-extension:markdown-language-features-server" + } +} diff --git a/extensions/markdown-language-features/server/src/browser/main.ts b/extensions/markdown-language-features/server/src/browser/main.ts new file mode 100644 index 00000000000..cc5e12e9c19 --- /dev/null +++ b/extensions/markdown-language-features/server/src/browser/main.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BrowserMessageReader, BrowserMessageWriter, createConnection } from 'vscode-languageserver/browser'; +import { startServer } from '../server'; + +declare let self: any; + +const messageReader = new BrowserMessageReader(self); +const messageWriter = new BrowserMessageWriter(self); + +const connection = createConnection(messageReader, messageWriter); + +startServer(connection); diff --git a/extensions/markdown-language-features/server/src/config.ts b/extensions/markdown-language-features/server/src/config.ts new file mode 100644 index 00000000000..6f9d85fbf1d --- /dev/null +++ b/extensions/markdown-language-features/server/src/config.ts @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LsConfiguration } from 'vscode-markdown-languageservice/out/config'; + +export { LsConfiguration }; + +const defaultConfig: LsConfiguration = { + markdownFileExtensions: ['md'], + knownLinkedToFileExtensions: [ + 'jpg', + 'jpeg', + 'png', + 'gif', + 'webp', + 'bmp', + 'tiff', + ], + excludePaths: [ + '**/.*', + '**/node_modules/**', + ] +}; + +export function getLsConfiguration(overrides: Partial): LsConfiguration { + return { + ...defaultConfig, + ...overrides, + }; +} diff --git a/extensions/markdown-language-features/server/src/configuration.ts b/extensions/markdown-language-features/server/src/configuration.ts new file mode 100644 index 00000000000..5066b3110a6 --- /dev/null +++ b/extensions/markdown-language-features/server/src/configuration.ts @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Connection, Emitter } from 'vscode-languageserver'; +import { Disposable } from './util/dispose'; + +export type ValidateEnabled = 'ignore' | 'warning' | 'error'; + +interface Settings { + readonly markdown: { + readonly suggest: { + readonly paths: { + readonly enabled: boolean; + }; + }; + + readonly experimental: { + readonly validate: { + readonly enabled: true; + readonly referenceLinks: { + readonly enabled: ValidateEnabled; + }; + readonly fragmentLinks: { + readonly enabled: ValidateEnabled; + }; + readonly fileLinks: { + readonly enabled: ValidateEnabled; + readonly markdownFragmentLinks: ValidateEnabled; + }; + readonly ignoreLinks: readonly string[]; + }; + }; + }; +} + + +export class ConfigurationManager extends Disposable { + + private readonly _onDidChangeConfiguration = this._register(new Emitter()); + public readonly onDidChangeConfiguration = this._onDidChangeConfiguration.event; + + private _settings?: Settings; + + constructor(connection: Connection) { + super(); + + // The settings have changed. Is send on server activation as well. + this._register(connection.onDidChangeConfiguration((change) => { + this._settings = change.settings; + this._onDidChangeConfiguration.fire(this._settings!); + })); + } + + public getSettings(): Settings | undefined { + return this._settings; + } +} \ No newline at end of file diff --git a/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts b/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts new file mode 100644 index 00000000000..9640f052ceb --- /dev/null +++ b/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Connection, FullDocumentDiagnosticReport, UnchangedDocumentDiagnosticReport } from 'vscode-languageserver'; +import * as md from 'vscode-markdown-languageservice'; +import { disposeAll } from 'vscode-markdown-languageservice/out/util/dispose'; +import { Disposable } from 'vscode-notebook-renderer/events'; +import { URI } from 'vscode-uri'; +import { ConfigurationManager, ValidateEnabled } from '../configuration'; +import { VsCodeClientWorkspace } from '../workspace'; + +const defaultDiagnosticOptions: md.DiagnosticOptions = { + validateFileLinks: md.DiagnosticLevel.ignore, + validateReferences: md.DiagnosticLevel.ignore, + validateFragmentLinks: md.DiagnosticLevel.ignore, + validateMarkdownFileLinkFragments: md.DiagnosticLevel.ignore, + ignoreLinks: [], +}; + +function convertDiagnosticLevel(enabled: ValidateEnabled): md.DiagnosticLevel | undefined { + switch (enabled) { + case 'error': return md.DiagnosticLevel.error; + case 'warning': return md.DiagnosticLevel.warning; + case 'ignore': return md.DiagnosticLevel.ignore; + default: return md.DiagnosticLevel.ignore; + } +} + +function getDiagnosticsOptions(config: ConfigurationManager): md.DiagnosticOptions { + const settings = config.getSettings(); + if (!settings) { + return defaultDiagnosticOptions; + } + + return { + validateFileLinks: convertDiagnosticLevel(settings.markdown.experimental.validate.fileLinks.enabled), + validateReferences: convertDiagnosticLevel(settings.markdown.experimental.validate.referenceLinks.enabled), + validateFragmentLinks: convertDiagnosticLevel(settings.markdown.experimental.validate.fragmentLinks.enabled), + validateMarkdownFileLinkFragments: convertDiagnosticLevel(settings.markdown.experimental.validate.fileLinks.markdownFragmentLinks), + ignoreLinks: settings.markdown.experimental.validate.ignoreLinks, + }; +} + +export function registerValidateSupport( + connection: Connection, + workspace: VsCodeClientWorkspace, + ls: md.IMdLanguageService, + config: ConfigurationManager, + logger: md.ILogger, +): Disposable { + let diagnosticOptions: md.DiagnosticOptions = defaultDiagnosticOptions; + function updateDiagnosticsSetting(): void { + diagnosticOptions = getDiagnosticsOptions(config); + } + + const subs: Disposable[] = []; + const manager = ls.createPullDiagnosticsManager(); + subs.push(manager); + + subs.push(manager.onLinkedToFileChanged(() => { + // TODO: We only need to refresh certain files + connection.languages.diagnostics.refresh(); + })); + + const emptyDiagnosticsResponse = Object.freeze({ kind: 'full', items: [] }); + + connection.languages.diagnostics.on(async (params, token): Promise => { + logger.log(md.LogLevel.Trace, 'Server: connection.languages.diagnostics.on', params.textDocument.uri); + + if (!config.getSettings()?.markdown.experimental.validate.enabled) { + return emptyDiagnosticsResponse; + } + + const uri = URI.parse(params.textDocument.uri); + if (!workspace.hasMarkdownDocument(uri)) { + return emptyDiagnosticsResponse; + } + + const document = await workspace.openMarkdownDocument(uri); + if (!document) { + return emptyDiagnosticsResponse; + } + + const diagnostics = await manager.computeDiagnostics(document, diagnosticOptions, token); + return { + kind: 'full', + items: diagnostics, + }; + }); + + updateDiagnosticsSetting(); + subs.push(config.onDidChangeConfiguration(() => { + updateDiagnosticsSetting(); + connection.languages.diagnostics.refresh(); + })); + + return { + dispose: () => { + disposeAll(subs); + } + }; +} diff --git a/extensions/markdown-language-features/server/src/logging.ts b/extensions/markdown-language-features/server/src/logging.ts new file mode 100644 index 00000000000..2fc08c25b7a --- /dev/null +++ b/extensions/markdown-language-features/server/src/logging.ts @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ILogger, LogLevel } from 'vscode-markdown-languageservice'; + +export class LogFunctionLogger implements ILogger { + + private static now(): string { + const now = new Date(); + return String(now.getUTCHours()).padStart(2, '0') + + ':' + String(now.getMinutes()).padStart(2, '0') + + ':' + String(now.getUTCSeconds()).padStart(2, '0') + '.' + String(now.getMilliseconds()).padStart(3, '0'); + } + + private static data2String(data: any): string { + if (data instanceof Error) { + if (typeof data.stack === 'string') { + return data.stack; + } + return data.message; + } + if (typeof data === 'string') { + return data; + } + return JSON.stringify(data, undefined, 2); + } + + constructor( + private readonly _logFn: typeof console.log + ) { } + + + public log(level: LogLevel, title: string, message: string, data?: any): void { + this.appendLine(`[${level} ${LogFunctionLogger.now()}] ${title}: ${message}`); + if (data) { + this.appendLine(LogFunctionLogger.data2String(data)); + } + } + + private appendLine(value: string): void { + this._logFn(value); + } +} + +export const consoleLogger = new LogFunctionLogger(console.log); diff --git a/extensions/markdown-language-features/server/src/node/main.ts b/extensions/markdown-language-features/server/src/node/main.ts new file mode 100644 index 00000000000..609948b803d --- /dev/null +++ b/extensions/markdown-language-features/server/src/node/main.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 { Connection, createConnection } from 'vscode-languageserver/node'; +import { startServer } from '../server'; + +// Create a connection for the server. +const connection: Connection = createConnection(); + +console.log = connection.console.log.bind(connection.console); +console.error = connection.console.error.bind(connection.console); + +process.on('unhandledRejection', (e: any) => { + connection.console.error(`Unhandled exception ${e}`); +}); + +startServer(connection); diff --git a/extensions/markdown-language-features/server/src/protocol.ts b/extensions/markdown-language-features/server/src/protocol.ts new file mode 100644 index 00000000000..ab407b4afc5 --- /dev/null +++ b/extensions/markdown-language-features/server/src/protocol.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { RequestType } from 'vscode-languageserver'; +import type * as lsp from 'vscode-languageserver-types'; +import type * as md from 'vscode-markdown-languageservice'; + +//#region From server +export const parse = new RequestType<{ uri: string }, md.Token[], any>('markdown/parse'); + +export const fs_readFile = new RequestType<{ uri: string }, number[], any>('markdown/fs/readFile'); +export const fs_readDirectory = new RequestType<{ uri: string }, [string, { isDirectory: boolean }][], any>('markdown/fs/readDirectory'); +export const fs_stat = new RequestType<{ uri: string }, { isDirectory: boolean } | undefined, any>('markdown/fs/stat'); + +export const fs_watcher_create = new RequestType<{ id: number; uri: string; options: md.FileWatcherOptions; watchParentDirs: boolean }, void, any>('markdown/fs/watcher/create'); +export const fs_watcher_delete = new RequestType<{ id: number }, void, any>('markdown/fs/watcher/delete'); + +export const findMarkdownFilesInWorkspace = new RequestType<{}, string[], any>('markdown/findMarkdownFilesInWorkspace'); +//#endregion + +//#region To server +export const getReferencesToFileInWorkspace = new RequestType<{ uri: string }, lsp.Location[], any>('markdown/getReferencesToFileInWorkspace'); +export const getEditForFileRenames = new RequestType, lsp.WorkspaceEdit, any>('markdown/getEditForFileRenames'); + +export const fs_watcher_onChange = new RequestType<{ id: number; uri: string; kind: 'create' | 'change' | 'delete' }, void, any>('markdown/fs/watcher/onChange'); + +export const resolveLinkTarget = new RequestType<{ linkText: string; uri: string }, md.ResolvedDocumentLinkTarget, any>('markdown/resolveLinkTarget'); +//#endregion diff --git a/extensions/markdown-language-features/server/src/server.ts b/extensions/markdown-language-features/server/src/server.ts new file mode 100644 index 00000000000..3f67d4117c7 --- /dev/null +++ b/extensions/markdown-language-features/server/src/server.ts @@ -0,0 +1,260 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancellationToken, Connection, InitializeParams, InitializeResult, NotebookDocuments, TextDocuments } from 'vscode-languageserver'; +import { TextDocument } from 'vscode-languageserver-textdocument'; +import * as lsp from 'vscode-languageserver-types'; +import * as md from 'vscode-markdown-languageservice'; +import * as nls from 'vscode-nls'; +import { URI } from 'vscode-uri'; +import { getLsConfiguration, LsConfiguration } from './config'; +import { ConfigurationManager } from './configuration'; +import { registerValidateSupport } from './languageFeatures/diagnostics'; +import { LogFunctionLogger } from './logging'; +import * as protocol from './protocol'; +import { IDisposable } from './util/dispose'; +import { VsCodeClientWorkspace } from './workspace'; + +const localize = nls.loadMessageBundle(); + +interface MdServerInitializationOptions extends LsConfiguration { } + +const organizeLinkDefKind = 'source.organizeLinkDefinitions'; +export async function startServer(connection: Connection) { + const documents = new TextDocuments(TextDocument); + const notebooks = new NotebookDocuments(documents); + + const configurationManager = new ConfigurationManager(connection); + + let mdLs: md.IMdLanguageService | undefined; + let workspace: VsCodeClientWorkspace | undefined; + + connection.onInitialize((params: InitializeParams): InitializeResult => { + const parser = new class implements md.IMdParser { + slugifier = md.githubSlugifier; + + async tokenize(document: md.ITextDocument): Promise { + return await connection.sendRequest(protocol.parse, { uri: document.uri.toString() }); + } + }; + + const initOptions = params.initializationOptions as MdServerInitializationOptions | undefined; + const config = getLsConfiguration(initOptions ?? {}); + + const logger = new LogFunctionLogger(connection.console.log.bind(connection.console)); + workspace = new VsCodeClientWorkspace(connection, config, documents, notebooks, logger); + mdLs = md.createLanguageService({ + workspace, + parser, + logger, + markdownFileExtensions: config.markdownFileExtensions, + excludePaths: config.excludePaths, + }); + + registerCompletionsSupport(connection, documents, mdLs, configurationManager); + registerValidateSupport(connection, workspace, mdLs, configurationManager, logger); + + workspace.workspaceFolders = (params.workspaceFolders ?? []).map(x => URI.parse(x.uri)); + return { + capabilities: { + diagnosticProvider: { + documentSelector: null, + identifier: 'markdown', + interFileDependencies: true, + workspaceDiagnostics: false, + }, + codeActionProvider: { resolveProvider: true }, + completionProvider: { triggerCharacters: ['.', '/', '#'] }, + definitionProvider: true, + documentLinkProvider: { resolveProvider: true }, + documentSymbolProvider: true, + foldingRangeProvider: true, + referencesProvider: true, + renameProvider: { prepareProvider: true, }, + selectionRangeProvider: true, + workspaceSymbolProvider: true, + workspace: { + workspaceFolders: { + supported: true, + changeNotifications: true, + }, + } + } + }; + }); + + connection.onDocumentLinks(async (params, token): Promise => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return []; + } + return mdLs!.getDocumentLinks(document, token); + }); + + connection.onDocumentLinkResolve(async (link, token): Promise => { + return mdLs!.resolveDocumentLink(link, token); + }); + + connection.onDocumentSymbol(async (params, token): Promise => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return []; + } + return mdLs!.getDocumentSymbols(document, { includeLinkDefinitions: true }, token); + }); + + connection.onFoldingRanges(async (params, token): Promise => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return []; + } + return mdLs!.getFoldingRanges(document, token); + }); + + connection.onSelectionRanges(async (params, token): Promise => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return []; + } + return mdLs!.getSelectionRanges(document, params.positions, token); + }); + + connection.onWorkspaceSymbol(async (params, token): Promise => { + return mdLs!.getWorkspaceSymbols(params.query, token); + }); + + connection.onReferences(async (params, token): Promise => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return []; + } + return mdLs!.getReferences(document, params.position, params.context, token); + }); + + connection.onDefinition(async (params, token): Promise => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return undefined; + } + return mdLs!.getDefinition(document, params.position, token); + }); + + connection.onPrepareRename(async (params, token) => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return undefined; + } + return mdLs!.prepareRename(document, params.position, token); + }); + + connection.onRenameRequest(async (params, token) => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return undefined; + } + return mdLs!.getRenameEdit(document, params.position, params.newName, token); + }); + + interface OrganizeLinkActionData { + readonly uri: string; + } + + connection.onCodeAction(async (params, token) => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return undefined; + } + + if (params.context.only?.some(kind => kind === 'source' || kind.startsWith('source.'))) { + const action: lsp.CodeAction = { + title: localize('organizeLinkDefAction.title', "Organize link definitions"), + kind: organizeLinkDefKind, + data: { uri: document.uri } + }; + return [action]; + } + + return mdLs!.getCodeActions(document, params.range, params.context, token); + }); + + connection.onCodeActionResolve(async (codeAction, token) => { + if (codeAction.kind === organizeLinkDefKind) { + const data = codeAction.data as OrganizeLinkActionData; + const document = documents.get(data.uri); + if (!document) { + return codeAction; + } + + const edits = (await mdLs?.organizeLinkDefinitions(document, { removeUnused: true }, token)) || []; + codeAction.edit = { + changes: { + [data.uri]: edits + } + }; + return codeAction; + } + + return codeAction; + }); + + connection.onRequest(protocol.getReferencesToFileInWorkspace, (async (params: { uri: string }, token: CancellationToken) => { + return mdLs!.getFileReferences(URI.parse(params.uri), token); + })); + + connection.onRequest(protocol.getEditForFileRenames, (async (params, token: CancellationToken) => { + return mdLs!.getRenameFilesInWorkspaceEdit(params.map(x => ({ oldUri: URI.parse(x.oldUri), newUri: URI.parse(x.newUri) })), token); + })); + + connection.onRequest(protocol.resolveLinkTarget, (async (params, token: CancellationToken) => { + return mdLs!.resolveLinkTarget(params.linkText, URI.parse(params.uri), token); + })); + + documents.listen(connection); + notebooks.listen(connection); + connection.listen(); +} + + +function registerCompletionsSupport( + connection: Connection, + documents: TextDocuments, + ls: md.IMdLanguageService, + config: ConfigurationManager, +): IDisposable { + // let registration: Promise | undefined; + function update() { + // TODO: client still makes the request in this case. Figure our how to properly unregister. + return; + // const settings = config.getSettings(); + // if (settings?.markdown.suggest.paths.enabled) { + // if (!registration) { + // registration = connection.client.register(CompletionRequest.type); + // } + // } else { + // registration?.then(x => x.dispose()); + // registration = undefined; + // } + } + + connection.onCompletion(async (params, token): Promise => { + try { + const settings = config.getSettings(); + if (!settings?.markdown.suggest.paths.enabled) { + return []; + } + + const document = documents.get(params.textDocument.uri); + if (document) { + return await ls.getCompletionItems(document, params.position, params.context!, token); + } + } catch (e) { + console.error(e.stack); + } + return []; + }); + + update(); + return config.onDidChangeConfiguration(() => update()); +} diff --git a/extensions/markdown-language-features/server/src/util/arrays.ts b/extensions/markdown-language-features/server/src/util/arrays.ts new file mode 100644 index 00000000000..3ed55d8f077 --- /dev/null +++ b/extensions/markdown-language-features/server/src/util/arrays.ts @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * @returns New array with all falsy values removed. The original array IS NOT modified. + */ +export function coalesce(array: ReadonlyArray): T[] { + return array.filter(e => !!e); +} diff --git a/extensions/markdown-language-features/server/src/util/dispose.ts b/extensions/markdown-language-features/server/src/util/dispose.ts new file mode 100644 index 00000000000..2e9d8dc6a14 --- /dev/null +++ b/extensions/markdown-language-features/server/src/util/dispose.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. + *--------------------------------------------------------------------------------------------*/ + +export function disposeAll(disposables: Iterable) { + const errors: any[] = []; + + for (const disposable of disposables) { + try { + disposable.dispose(); + } catch (e) { + errors.push(e); + } + } + + if (errors.length === 1) { + throw errors[0]; + } else if (errors.length > 1) { + throw new AggregateError(errors, 'Encountered errors while disposing of store'); + } +} + +export interface IDisposable { + dispose(): void; +} + +export abstract class Disposable { + private _isDisposed = false; + + protected _disposables: IDisposable[] = []; + + public dispose(): any { + if (this._isDisposed) { + return; + } + this._isDisposed = true; + disposeAll(this._disposables); + } + + protected _register(value: T): T { + if (this._isDisposed) { + value.dispose(); + } else { + this._disposables.push(value); + } + return value; + } + + protected get isDisposed() { + return this._isDisposed; + } +} + diff --git a/extensions/markdown-language-features/server/src/util/file.ts b/extensions/markdown-language-features/server/src/util/file.ts new file mode 100644 index 00000000000..b8d1286a42c --- /dev/null +++ b/extensions/markdown-language-features/server/src/util/file.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { TextDocument } from 'vscode-languageserver-textdocument'; +import { URI, Utils } from 'vscode-uri'; +import { LsConfiguration } from '../config'; + +export function looksLikeMarkdownPath(config: LsConfiguration, resolvedHrefPath: URI) { + return config.markdownFileExtensions.includes(Utils.extname(URI.from(resolvedHrefPath)).toLowerCase().replace('.', '')); +} + +export function isMarkdownFile(document: TextDocument) { + return document.languageId === 'markdown'; +} diff --git a/extensions/markdown-language-features/src/util/limiter.ts b/extensions/markdown-language-features/server/src/util/limiter.ts similarity index 100% rename from extensions/markdown-language-features/src/util/limiter.ts rename to extensions/markdown-language-features/server/src/util/limiter.ts diff --git a/extensions/markdown-language-features/server/src/util/resourceMap.ts b/extensions/markdown-language-features/server/src/util/resourceMap.ts new file mode 100644 index 00000000000..7cec9d661d3 --- /dev/null +++ b/extensions/markdown-language-features/server/src/util/resourceMap.ts @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vscode-uri'; + + +type ResourceToKey = (uri: URI) => string; + +const defaultResourceToKey = (resource: URI): string => resource.toString(); + +export class ResourceMap { + + private readonly map = new Map(); + + private readonly toKey: ResourceToKey; + + constructor(toKey: ResourceToKey = defaultResourceToKey) { + this.toKey = toKey; + } + + public set(uri: URI, value: T): this { + this.map.set(this.toKey(uri), { uri, value }); + return this; + } + + public get(resource: URI): T | undefined { + return this.map.get(this.toKey(resource))?.value; + } + + public has(resource: URI): boolean { + return this.map.has(this.toKey(resource)); + } + + public get size(): number { + return this.map.size; + } + + public clear(): void { + this.map.clear(); + } + + public delete(resource: URI): boolean { + return this.map.delete(this.toKey(resource)); + } + + public *values(): IterableIterator { + for (const entry of this.map.values()) { + yield entry.value; + } + } + + public *keys(): IterableIterator { + for (const entry of this.map.values()) { + yield entry.uri; + } + } + + public *entries(): IterableIterator<[URI, T]> { + for (const entry of this.map.values()) { + yield [entry.uri, entry.value]; + } + } + + public [Symbol.iterator](): IterableIterator<[URI, T]> { + return this.entries(); + } +} diff --git a/extensions/markdown-language-features/server/src/util/schemes.ts b/extensions/markdown-language-features/server/src/util/schemes.ts new file mode 100644 index 00000000000..67b75e0a0d6 --- /dev/null +++ b/extensions/markdown-language-features/server/src/util/schemes.ts @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export const Schemes = Object.freeze({ + notebookCell: 'vscode-notebook-cell', +}); diff --git a/extensions/markdown-language-features/server/src/workspace.ts b/extensions/markdown-language-features/server/src/workspace.ts new file mode 100644 index 00000000000..0389055807a --- /dev/null +++ b/extensions/markdown-language-features/server/src/workspace.ts @@ -0,0 +1,262 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Connection, Emitter, FileChangeType, NotebookDocuments, TextDocuments } from 'vscode-languageserver'; +import { TextDocument } from 'vscode-languageserver-textdocument'; +import * as md from 'vscode-markdown-languageservice'; +import { ContainingDocumentContext, FileWatcherOptions, IFileSystemWatcher } from 'vscode-markdown-languageservice/out/workspace'; +import { URI } from 'vscode-uri'; +import { LsConfiguration } from './config'; +import * as protocol from './protocol'; +import { isMarkdownFile, looksLikeMarkdownPath } from './util/file'; +import { Limiter } from './util/limiter'; +import { ResourceMap } from './util/resourceMap'; +import { Schemes } from './util/schemes'; + +declare const TextDecoder: any; + +export class VsCodeClientWorkspace implements md.IWorkspaceWithWatching { + + private readonly _onDidCreateMarkdownDocument = new Emitter(); + public readonly onDidCreateMarkdownDocument = this._onDidCreateMarkdownDocument.event; + + private readonly _onDidChangeMarkdownDocument = new Emitter(); + public readonly onDidChangeMarkdownDocument = this._onDidChangeMarkdownDocument.event; + + private readonly _onDidDeleteMarkdownDocument = new Emitter(); + public readonly onDidDeleteMarkdownDocument = this._onDidDeleteMarkdownDocument.event; + + private readonly _documentCache = new ResourceMap(); + + private readonly _utf8Decoder = new TextDecoder('utf-8'); + + private _watcherPool = 0; + private readonly _watchers = new Map; + readonly onDidCreate: Emitter; + readonly onDidDelete: Emitter; + }>(); + + constructor( + private readonly connection: Connection, + private readonly config: LsConfiguration, + private readonly documents: TextDocuments, + private readonly notebooks: NotebookDocuments, + private readonly logger: md.ILogger, + ) { + documents.onDidOpen(e => { + this._documentCache.delete(URI.parse(e.document.uri)); + if (this.isRelevantMarkdownDocument(e.document)) { + this._onDidCreateMarkdownDocument.fire(e.document); + } + }); + + documents.onDidChangeContent(e => { + if (this.isRelevantMarkdownDocument(e.document)) { + this._onDidChangeMarkdownDocument.fire(e.document); + } + }); + + documents.onDidClose(e => { + const uri = URI.parse(e.document.uri); + this._documentCache.delete(uri); + + if (this.isRelevantMarkdownDocument(e.document)) { + this._onDidDeleteMarkdownDocument.fire(uri); + } + }); + + connection.onDidChangeWatchedFiles(async ({ changes }) => { + for (const change of changes) { + const resource = URI.parse(change.uri); + this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: onDidChangeWatchedFiles', `${change.type}: ${resource}`); + switch (change.type) { + case FileChangeType.Changed: { + this._documentCache.delete(resource); + const document = await this.openMarkdownDocument(resource); + if (document) { + this._onDidChangeMarkdownDocument.fire(document); + } + break; + } + case FileChangeType.Created: { + const document = await this.openMarkdownDocument(resource); + if (document) { + this._onDidCreateMarkdownDocument.fire(document); + } + break; + } + case FileChangeType.Deleted: { + this._documentCache.delete(resource); + this._onDidDeleteMarkdownDocument.fire(resource); + break; + } + } + } + }); + + connection.onRequest(protocol.fs_watcher_onChange, params => { + this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: fs_watcher_onChange', `${params.kind}: ${params.uri}`); + + const watcher = this._watchers.get(params.id); + if (!watcher) { + return; + } + + switch (params.kind) { + case 'create': watcher.onDidCreate.fire(URI.parse(params.uri)); return; + case 'change': watcher.onDidChange.fire(URI.parse(params.uri)); return; + case 'delete': watcher.onDidDelete.fire(URI.parse(params.uri)); return; + } + }); + } + + public listen() { + this.connection.workspace.onDidChangeWorkspaceFolders(async () => { + this.workspaceFolders = (await this.connection.workspace.getWorkspaceFolders() ?? []).map(x => URI.parse(x.uri)); + }); + } + + private _workspaceFolders: readonly URI[] = []; + + get workspaceFolders(): readonly URI[] { + return this._workspaceFolders; + } + + set workspaceFolders(value: readonly URI[]) { + this._workspaceFolders = value; + } + + async getAllMarkdownDocuments(): Promise> { + // Add opened files (such as untitled files) + const openTextDocumentResults = this.documents.all() + .filter(doc => this.isRelevantMarkdownDocument(doc)); + + const allDocs = new ResourceMap(); + for (const doc of openTextDocumentResults) { + allDocs.set(URI.parse(doc.uri), doc); + } + + // And then add files on disk + const maxConcurrent = 20; + const limiter = new Limiter(maxConcurrent); + const resources = await this.connection.sendRequest(protocol.findMarkdownFilesInWorkspace, {}); + await Promise.all(resources.map(strResource => { + return limiter.queue(async () => { + const resource = URI.parse(strResource); + if (allDocs.has(resource)) { + return; + } + + const doc = await this.openMarkdownDocument(resource); + if (doc) { + allDocs.set(resource, doc); + } + return doc; + }); + })); + + return allDocs.values(); + } + + hasMarkdownDocument(resource: URI): boolean { + return !!this.documents.get(resource.toString()); + } + + async openMarkdownDocument(resource: URI): Promise { + const existing = this._documentCache.get(resource); + if (existing) { + return existing; + } + + const matchingDocument = this.documents.get(resource.toString()); + if (matchingDocument) { + this._documentCache.set(resource, matchingDocument); + return matchingDocument; + } + + if (!looksLikeMarkdownPath(this.config, resource)) { + return undefined; + } + + try { + const response = await this.connection.sendRequest(protocol.fs_readFile, { uri: resource.toString() }); + // TODO: LSP doesn't seem to handle Array buffers well + const bytes = new Uint8Array(response); + + // We assume that markdown is in UTF-8 + const text = this._utf8Decoder.decode(bytes); + const doc = TextDocument.create(resource.toString(), 'markdown', 0, text); + this._documentCache.set(resource, doc); + return doc; + } catch (e) { + return undefined; + } + } + + async stat(resource: URI): Promise { + this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: stat', `${resource}`); + if (this._documentCache.has(resource) || this.documents.get(resource.toString())) { + return { isDirectory: false }; + } + return this.connection.sendRequest(protocol.fs_stat, { uri: resource.toString() }); + } + + async readDirectory(resource: URI): Promise<[string, md.FileStat][]> { + this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: readDir', `${resource}`); + return this.connection.sendRequest(protocol.fs_readDirectory, { uri: resource.toString() }); + } + + getContainingDocument(resource: URI): ContainingDocumentContext | undefined { + if (resource.scheme === Schemes.notebookCell) { + const nb = this.notebooks.findNotebookDocumentForCell(resource.toString()); + if (nb) { + return { + uri: URI.parse(nb.uri), + children: nb.cells.map(cell => ({ uri: URI.parse(cell.document) })), + }; + } + } + return undefined; + } + + watchFile(resource: URI, options: FileWatcherOptions): IFileSystemWatcher { + const id = this._watcherPool++; + this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: watchFile', `(${id}) ${resource}`); + + const entry = { + resource, + options, + onDidCreate: new Emitter(), + onDidChange: new Emitter(), + onDidDelete: new Emitter(), + }; + this._watchers.set(id, entry); + + this.connection.sendRequest(protocol.fs_watcher_create, { + id, + uri: resource.toString(), + options, + watchParentDirs: true, + }); + + return { + onDidCreate: entry.onDidCreate.event, + onDidChange: entry.onDidChange.event, + onDidDelete: entry.onDidDelete.event, + dispose: () => { + this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: disposeWatcher', `(${id}) ${resource}`); + this.connection.sendRequest(protocol.fs_watcher_delete, { id }); + this._watchers.delete(id); + } + }; + } + + private isRelevantMarkdownDocument(doc: TextDocument) { + return isMarkdownFile(doc) && URI.parse(doc.uri).scheme !== 'vscode-bulkeditpreview'; + } +} diff --git a/extensions/markdown-language-features/server/tsconfig.json b/extensions/markdown-language-features/server/tsconfig.json new file mode 100644 index 00000000000..8b4aedde27d --- /dev/null +++ b/extensions/markdown-language-features/server/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out" + }, + "include": [ + "src/**/*" + ] +} diff --git a/extensions/markdown-language-features/server/yarn.lock b/extensions/markdown-language-features/server/yarn.lock new file mode 100644 index 00000000000..803846a6d76 --- /dev/null +++ b/extensions/markdown-language-features/server/yarn.lock @@ -0,0 +1,64 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@16.x": + version "16.11.47" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.47.tgz#efa9e3e0f72e7aa6a138055dace7437a83d9f91c" + integrity sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +vscode-jsonrpc@8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz#f239ed2cd6004021b6550af9fd9d3e47eee3cac9" + integrity sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ== + +vscode-languageserver-protocol@3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz#beaa46aea06ed061576586c5e11368a9afc1d378" + integrity sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg== + dependencies: + vscode-jsonrpc "8.0.2" + vscode-languageserver-types "3.17.2" + +vscode-languageserver-textdocument@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.5.tgz#838769940ece626176ec5d5a2aa2d0aa69f5095c" + integrity sha512-1ah7zyQjKBudnMiHbZmxz5bYNM9KKZYz+5VQLj+yr8l+9w3g+WAhCkUkWbhMEdC5u0ub4Ndiye/fDyS8ghIKQg== + +vscode-languageserver-types@3.17.2, vscode-languageserver-types@^3.17.1: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== + +vscode-languageserver@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz#cfe2f0996d9dfd40d3854e786b2821604dfec06d" + integrity sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA== + dependencies: + vscode-languageserver-protocol "3.17.2" + +vscode-markdown-languageservice@^0.1.0-alpha.2: + version "0.1.0-alpha.2" + resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.1.0-alpha.2.tgz#e74f92e5e0805cf2107af5043911caad01e58d68" + integrity sha512-MKvp1dtZ4ZKNOL8bAvRKWvaayqBw1Ai6JY3zApqFwYGE0sWLrMZZBmFCkyb+boRJ3k55cepkgW5cQNVY13295w== + dependencies: + picomatch "^2.3.1" + vscode-languageserver-textdocument "^1.0.5" + vscode-languageserver-types "^3.17.1" + vscode-nls "^5.0.1" + vscode-uri "^3.0.3" + +vscode-nls@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== + +vscode-uri@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" + integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== diff --git a/extensions/markdown-language-features/src/client.ts b/extensions/markdown-language-features/src/client.ts new file mode 100644 index 00000000000..59952aaa87b --- /dev/null +++ b/extensions/markdown-language-features/src/client.ts @@ -0,0 +1,213 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { BaseLanguageClient, LanguageClientOptions, NotebookDocumentSyncRegistrationType } from 'vscode-languageclient'; +import { disposeAll, IDisposable } from 'vscode-markdown-languageservice/out/util/dispose'; +import { ResourceMap } from 'vscode-markdown-languageservice/out/util/resourceMap'; +import * as nls from 'vscode-nls'; +import { Utils } from 'vscode-uri'; +import { IMdParser } from './markdownEngine'; +import * as proto from './protocol'; +import { looksLikeMarkdownPath, markdownFileExtensions } from './util/file'; +import { Schemes } from './util/schemes'; +import { IMdWorkspace } from './workspace'; + +const localize = nls.loadMessageBundle(); + +export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient; + + +export async function startClient(factory: LanguageClientConstructor, workspace: IMdWorkspace, parser: IMdParser): Promise { + + const mdFileGlob = `**/*.{${markdownFileExtensions.join(',')}}`; + + const clientOptions: LanguageClientOptions = { + documentSelector: [{ language: 'markdown' }], + synchronize: { + configurationSection: ['markdown'], + fileEvents: vscode.workspace.createFileSystemWatcher(mdFileGlob), + }, + initializationOptions: { + markdownFileExtensions, + }, + diagnosticPullOptions: { + onChange: true, + onTabs: true, + match(_documentSelector, resource) { + return looksLikeMarkdownPath(resource); + }, + }, + }; + + const client = factory('markdown', localize('markdownServer.name', 'Markdown Language Server'), clientOptions); + + client.registerProposedFeatures(); + + const notebookFeature = client.getFeature(NotebookDocumentSyncRegistrationType.method); + if (notebookFeature !== undefined) { + notebookFeature.register({ + id: String(Date.now()), + registerOptions: { + notebookSelector: [{ + notebook: '*', + cells: [{ language: 'markdown' }] + }] + } + }); + } + + client.onRequest(proto.parse, async (e) => { + const uri = vscode.Uri.parse(e.uri); + const doc = await workspace.getOrLoadMarkdownDocument(uri); + if (doc) { + return parser.tokenize(doc); + } else { + return []; + } + }); + + client.onRequest(proto.fs_readFile, async (e): Promise => { + const uri = vscode.Uri.parse(e.uri); + return Array.from(await vscode.workspace.fs.readFile(uri)); + }); + + client.onRequest(proto.fs_stat, async (e): Promise<{ isDirectory: boolean } | undefined> => { + const uri = vscode.Uri.parse(e.uri); + try { + const stat = await vscode.workspace.fs.stat(uri); + return { isDirectory: stat.type === vscode.FileType.Directory }; + } catch { + return undefined; + } + }); + + client.onRequest(proto.fs_readDirectory, async (e): Promise<[string, { isDirectory: boolean }][]> => { + const uri = vscode.Uri.parse(e.uri); + const result = await vscode.workspace.fs.readDirectory(uri); + return result.map(([name, type]) => [name, { isDirectory: type === vscode.FileType.Directory }]); + }); + + client.onRequest(proto.findMarkdownFilesInWorkspace, async (): Promise => { + return (await vscode.workspace.findFiles(mdFileGlob, '**/node_modules/**')).map(x => x.toString()); + }); + + const watchers = new FileWatcherManager(); + + client.onRequest(proto.fs_watcher_create, async (params): Promise => { + const id = params.id; + const uri = vscode.Uri.parse(params.uri); + + const sendWatcherChange = (kind: 'create' | 'change' | 'delete') => { + client.sendRequest(proto.fs_watcher_onChange, { id, uri: params.uri, kind }); + }; + + watchers.create(id, uri, params.watchParentDirs, { + create: params.options.ignoreCreate ? undefined : () => sendWatcherChange('create'), + change: params.options.ignoreChange ? undefined : () => sendWatcherChange('change'), + delete: params.options.ignoreDelete ? undefined : () => sendWatcherChange('delete'), + }); + }); + + client.onRequest(proto.fs_watcher_delete, async (params): Promise => { + watchers.delete(params.id); + }); + + vscode.commands.registerCommand('vscodeMarkdownLanguageservice.open', (uri, args) => { + return vscode.commands.executeCommand('vscode.open', uri, args); + }); + + await client.start(); + + return client; +} + +type DirWatcherEntry = { + readonly uri: vscode.Uri; + readonly listeners: IDisposable[]; +}; + +class FileWatcherManager { + + private readonly fileWatchers = new Map(); + + private readonly dirWatchers = new ResourceMap<{ + readonly watcher: vscode.FileSystemWatcher; + refCount: number; + }>(); + + create(id: number, uri: vscode.Uri, watchParentDirs: boolean, listeners: { create?: () => void; change?: () => void; delete?: () => void }): void { + const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(uri, '*'), !listeners.create, !listeners.change, !listeners.delete); + const parentDirWatchers: DirWatcherEntry[] = []; + this.fileWatchers.set(id, { watcher, dirWatchers: parentDirWatchers }); + + if (listeners.create) { watcher.onDidCreate(listeners.create); } + if (listeners.change) { watcher.onDidChange(listeners.change); } + if (listeners.delete) { watcher.onDidDelete(listeners.delete); } + + if (watchParentDirs && uri.scheme !== Schemes.untitled) { + // We need to watch the parent directories too for when these are deleted / created + for (let dirUri = Utils.dirname(uri); dirUri.path.length > 1; dirUri = Utils.dirname(dirUri)) { + const dirWatcher: DirWatcherEntry = { uri: dirUri, listeners: [] }; + + let parentDirWatcher = this.dirWatchers.get(dirUri); + if (!parentDirWatcher) { + const glob = new vscode.RelativePattern(Utils.dirname(dirUri), Utils.basename(dirUri)); + const parentWatcher = vscode.workspace.createFileSystemWatcher(glob, !listeners.create, true, !listeners.delete); + parentDirWatcher = { refCount: 0, watcher: parentWatcher }; + this.dirWatchers.set(dirUri, parentDirWatcher); + } + parentDirWatcher.refCount++; + + if (listeners.create) { + dirWatcher.listeners.push(parentDirWatcher.watcher.onDidCreate(async () => { + // Just because the parent dir was created doesn't mean our file was created + try { + const stat = await vscode.workspace.fs.stat(uri); + if (stat.type === vscode.FileType.File) { + listeners.create!(); + } + } catch { + // Noop + } + })); + } + + if (listeners.delete) { + // When the parent dir is deleted, consider our file deleted too + + // TODO: this fires if the file previously did not exist and then the parent is deleted + dirWatcher.listeners.push(parentDirWatcher.watcher.onDidDelete(listeners.delete)); + } + + parentDirWatchers.push(dirWatcher); + } + } + } + + delete(id: number): void { + const entry = this.fileWatchers.get(id); + if (entry) { + for (const dirWatcher of entry.dirWatchers) { + disposeAll(dirWatcher.listeners); + + const dirWatcherEntry = this.dirWatchers.get(dirWatcher.uri); + if (dirWatcherEntry) { + if (--dirWatcherEntry.refCount <= 0) { + dirWatcherEntry.watcher.dispose(); + this.dirWatchers.delete(dirWatcher.uri); + } + } + } + + entry.watcher.dispose(); + } + + this.fileWatchers.delete(id); + } +} diff --git a/extensions/markdown-language-features/src/commands/index.ts b/extensions/markdown-language-features/src/commands/index.ts index d810fab4931..b93a9d2ed2a 100644 --- a/extensions/markdown-language-features/src/commands/index.ts +++ b/extensions/markdown-language-features/src/commands/index.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export { MoveCursorToPositionCommand } from './moveCursorToPosition'; -export { OpenDocumentLinkCommand } from './openDocumentLink'; export { RefreshPreviewCommand } from './refreshPreview'; export { ReloadPlugins } from './reloadPlugins'; export { RenderDocument } from './renderDocument'; diff --git a/extensions/markdown-language-features/src/commands/moveCursorToPosition.ts b/extensions/markdown-language-features/src/commands/moveCursorToPosition.ts deleted file mode 100644 index c0d175f370d..00000000000 --- a/extensions/markdown-language-features/src/commands/moveCursorToPosition.ts +++ /dev/null @@ -1,21 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { Command } from '../commandManager'; - -export class MoveCursorToPositionCommand implements Command { - public readonly id = '_markdown.moveCursorToPosition'; - - public execute(line: number, character: number) { - if (!vscode.window.activeTextEditor) { - return; - } - const position = new vscode.Position(line, character); - const selection = new vscode.Selection(position, position); - vscode.window.activeTextEditor.revealRange(selection); - vscode.window.activeTextEditor.selection = selection; - } -} diff --git a/extensions/markdown-language-features/src/commands/openDocumentLink.ts b/extensions/markdown-language-features/src/commands/openDocumentLink.ts deleted file mode 100644 index 1b061c9c4e4..00000000000 --- a/extensions/markdown-language-features/src/commands/openDocumentLink.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 * as vscode from 'vscode'; -import { Command } from '../commandManager'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { openDocumentLink } from '../util/openDocumentLink'; -import { Schemes } from '../util/schemes'; - -type UriComponents = { - readonly scheme?: string; - readonly path: string; - readonly fragment?: string; - readonly authority?: string; - readonly query?: string; -}; - -export interface OpenDocumentLinkArgs { - readonly parts: UriComponents; - readonly fragment: string; - readonly fromResource: UriComponents; -} - -export class OpenDocumentLinkCommand implements Command { - private static readonly id = '_markdown.openDocumentLink'; - public readonly id = OpenDocumentLinkCommand.id; - - public static createCommandUri( - fromResource: vscode.Uri, - path: vscode.Uri, - fragment: string, - ): vscode.Uri { - const toJson = (uri: vscode.Uri): UriComponents => { - return { - scheme: uri.scheme, - authority: uri.authority, - path: uri.path, - fragment: uri.fragment, - query: uri.query, - }; - }; - return vscode.Uri.parse(`command:${OpenDocumentLinkCommand.id}?${encodeURIComponent(JSON.stringify({ - parts: toJson(path), - fragment, - fromResource: toJson(fromResource), - }))}`); - } - - public constructor( - private readonly tocProvider: MdTableOfContentsProvider, - ) { } - - public async execute(args: OpenDocumentLinkArgs) { - const fromResource = vscode.Uri.parse('').with(args.fromResource); - const targetResource = reviveUri(args.parts).with({ fragment: args.fragment }); - return openDocumentLink(this.tocProvider, targetResource, fromResource); - } -} - -function reviveUri(parts: any) { - if (parts.scheme === Schemes.file) { - return vscode.Uri.file(parts.path); - } - return vscode.Uri.parse('').with(parts); -} diff --git a/extensions/markdown-language-features/src/extension.browser.ts b/extensions/markdown-language-features/src/extension.browser.ts new file mode 100644 index 00000000000..f1c860fbc86 --- /dev/null +++ b/extensions/markdown-language-features/src/extension.browser.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { BaseLanguageClient, LanguageClient, LanguageClientOptions } from 'vscode-languageclient/browser'; +import { startClient } from './client'; +import { activateShared } from './extension.shared'; +import { VsCodeOutputLogger } from './logging'; +import { IMdParser, MarkdownItEngine } from './markdownEngine'; +import { getMarkdownExtensionContributions } from './markdownExtensions'; +import { githubSlugifier } from './slugify'; +import { IMdWorkspace, VsCodeMdWorkspace } from './workspace'; + +export async function activate(context: vscode.ExtensionContext) { + const contributions = getMarkdownExtensionContributions(context); + context.subscriptions.push(contributions); + + const logger = new VsCodeOutputLogger(); + context.subscriptions.push(logger); + + const engine = new MarkdownItEngine(contributions, githubSlugifier, logger); + + const workspace = new VsCodeMdWorkspace(); + context.subscriptions.push(workspace); + + const client = await startServer(context, workspace, engine); + context.subscriptions.push({ + dispose: () => client.stop() + }); + activateShared(context, client, engine, logger, contributions); +} + +function startServer(context: vscode.ExtensionContext, workspace: IMdWorkspace, parser: IMdParser): Promise { + const serverMain = vscode.Uri.joinPath(context.extensionUri, 'server/dist/browser/main.js'); + const worker = new Worker(serverMain.toString()); + + return startClient((id: string, name: string, clientOptions: LanguageClientOptions) => { + return new LanguageClient(id, name, clientOptions, worker); + }, workspace, parser); +} diff --git a/extensions/markdown-language-features/src/extension.shared.ts b/extensions/markdown-language-features/src/extension.shared.ts new file mode 100644 index 00000000000..2ce5a5010e1 --- /dev/null +++ b/extensions/markdown-language-features/src/extension.shared.ts @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { BaseLanguageClient } from 'vscode-languageclient'; +import { CommandManager } from './commandManager'; +import * as commands from './commands/index'; +import { registerPasteSupport } from './languageFeatures/copyPaste'; +import { registerDiagnosticSupport } from './languageFeatures/diagnostics'; +import { registerDropIntoEditorSupport } from './languageFeatures/dropIntoEditor'; +import { registerFindFileReferenceSupport } from './languageFeatures/fileReferences'; +import { registerUpdateLinksOnRename } from './languageFeatures/linkUpdater'; +import { ILogger } from './logging'; +import { MarkdownItEngine } from './markdownEngine'; +import { MarkdownContributionProvider } from './markdownExtensions'; +import { MdDocumentRenderer } from './preview/documentRenderer'; +import { MarkdownPreviewManager } from './preview/previewManager'; +import { ContentSecurityPolicyArbiter, ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector } from './preview/security'; +import { loadDefaultTelemetryReporter, TelemetryReporter } from './telemetryReporter'; +import { MdLinkOpener } from './util/openDocumentLink'; + +export function activateShared( + context: vscode.ExtensionContext, + client: BaseLanguageClient, + engine: MarkdownItEngine, + logger: ILogger, + contributions: MarkdownContributionProvider, +) { + const telemetryReporter = loadDefaultTelemetryReporter(); + context.subscriptions.push(telemetryReporter); + + const cspArbiter = new ExtensionContentSecurityPolicyArbiter(context.globalState, context.workspaceState); + const commandManager = new CommandManager(); + + const opener = new MdLinkOpener(client); + + const contentProvider = new MdDocumentRenderer(engine, context, cspArbiter, contributions, logger); + const previewManager = new MarkdownPreviewManager(contentProvider, logger, contributions, opener); + context.subscriptions.push(previewManager); + + context.subscriptions.push(registerMarkdownLanguageFeatures(client, commandManager)); + context.subscriptions.push(registerMarkdownCommands(commandManager, previewManager, telemetryReporter, cspArbiter, engine)); + + context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => { + previewManager.updateConfiguration(); + })); +} + +function registerMarkdownLanguageFeatures( + client: BaseLanguageClient, + commandManager: CommandManager, +): vscode.Disposable { + const selector: vscode.DocumentSelector = { language: 'markdown', scheme: '*' }; + return vscode.Disposable.from( + // Language features + registerDiagnosticSupport(selector, commandManager), + registerDropIntoEditorSupport(selector), + registerFindFileReferenceSupport(commandManager, client), + registerPasteSupport(selector), + registerUpdateLinksOnRename(client), + ); +} + +function registerMarkdownCommands( + commandManager: CommandManager, + previewManager: MarkdownPreviewManager, + telemetryReporter: TelemetryReporter, + cspArbiter: ContentSecurityPolicyArbiter, + engine: MarkdownItEngine, +): vscode.Disposable { + const previewSecuritySelector = new PreviewSecuritySelector(cspArbiter, previewManager); + + commandManager.register(new commands.ShowPreviewCommand(previewManager, telemetryReporter)); + commandManager.register(new commands.ShowPreviewToSideCommand(previewManager, telemetryReporter)); + commandManager.register(new commands.ShowLockedPreviewToSideCommand(previewManager, telemetryReporter)); + commandManager.register(new commands.ShowSourceCommand(previewManager)); + commandManager.register(new commands.RefreshPreviewCommand(previewManager, engine)); + commandManager.register(new commands.ShowPreviewSecuritySelectorCommand(previewSecuritySelector, previewManager)); + commandManager.register(new commands.ToggleLockCommand(previewManager)); + commandManager.register(new commands.RenderDocument(engine)); + commandManager.register(new commands.ReloadPlugins(previewManager, engine)); + return commandManager; +} diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts index 32eef08f82e..5d8cba9200b 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.ts @@ -4,118 +4,50 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { CommandManager } from './commandManager'; -import * as commands from './commands/index'; -import { registerPasteSupport } from './languageFeatures/copyPaste'; -import { registerDefinitionSupport } from './languageFeatures/definitions'; -import { registerDiagnosticSupport } from './languageFeatures/diagnostics'; -import { MdLinkProvider, registerDocumentLinkSupport } from './languageFeatures/documentLinks'; -import { MdDocumentSymbolProvider, registerDocumentSymbolSupport } from './languageFeatures/documentSymbols'; -import { registerDropIntoEditorSupport } from './languageFeatures/dropIntoEditor'; -import { registerFindFileReferenceSupport } from './languageFeatures/fileReferences'; -import { registerFoldingSupport } from './languageFeatures/folding'; -import { registerPathCompletionSupport } from './languageFeatures/pathCompletions'; -import { MdReferencesProvider, registerReferencesSupport } from './languageFeatures/references'; -import { registerRenameSupport } from './languageFeatures/rename'; -import { registerSmartSelectSupport } from './languageFeatures/smartSelect'; -import { registerWorkspaceSymbolSupport } from './languageFeatures/workspaceSymbols'; -import { ILogger, VsCodeOutputLogger } from './logging'; -import { IMdParser, MarkdownItEngine, MdParsingProvider } from './markdownEngine'; +import { BaseLanguageClient, LanguageClient, ServerOptions, TransportKind } from 'vscode-languageclient/node'; +import { startClient } from './client'; +import { activateShared } from './extension.shared'; +import { VsCodeOutputLogger } from './logging'; +import { IMdParser, MarkdownItEngine } from './markdownEngine'; import { getMarkdownExtensionContributions } from './markdownExtensions'; -import { MdDocumentRenderer } from './preview/documentRenderer'; -import { MarkdownPreviewManager } from './preview/previewManager'; -import { ContentSecurityPolicyArbiter, ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector } from './preview/security'; import { githubSlugifier } from './slugify'; -import { MdTableOfContentsProvider } from './tableOfContents'; -import { loadDefaultTelemetryReporter, TelemetryReporter } from './telemetryReporter'; import { IMdWorkspace, VsCodeMdWorkspace } from './workspace'; - -export function activate(context: vscode.ExtensionContext) { - const telemetryReporter = loadDefaultTelemetryReporter(); - context.subscriptions.push(telemetryReporter); - +export async function activate(context: vscode.ExtensionContext) { const contributions = getMarkdownExtensionContributions(context); context.subscriptions.push(contributions); const logger = new VsCodeOutputLogger(); context.subscriptions.push(logger); - const cspArbiter = new ExtensionContentSecurityPolicyArbiter(context.globalState, context.workspaceState); - const commandManager = new CommandManager(); - const engine = new MarkdownItEngine(contributions, githubSlugifier, logger); + const workspace = new VsCodeMdWorkspace(); - const parser = new MdParsingProvider(engine, workspace); - const tocProvider = new MdTableOfContentsProvider(parser, workspace, logger); - context.subscriptions.push(workspace, parser, tocProvider); + context.subscriptions.push(workspace); - const contentProvider = new MdDocumentRenderer(engine, context, cspArbiter, contributions, logger); - const previewManager = new MarkdownPreviewManager(contentProvider, workspace, logger, contributions, tocProvider); - context.subscriptions.push(previewManager); - - context.subscriptions.push(registerMarkdownLanguageFeatures(parser, workspace, commandManager, tocProvider, logger)); - context.subscriptions.push(registerMarkdownCommands(commandManager, previewManager, telemetryReporter, cspArbiter, engine, tocProvider)); - - context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => { - previewManager.updateConfiguration(); - })); + const client = await startServer(context, workspace, engine); + context.subscriptions.push({ + dispose: () => client.stop() + }); + activateShared(context, client, engine, logger, contributions); } -function registerMarkdownLanguageFeatures( - parser: IMdParser, - workspace: IMdWorkspace, - commandManager: CommandManager, - tocProvider: MdTableOfContentsProvider, - logger: ILogger, -): vscode.Disposable { - const selector: vscode.DocumentSelector = { language: 'markdown', scheme: '*' }; +function startServer(context: vscode.ExtensionContext, workspace: IMdWorkspace, parser: IMdParser): Promise { + const clientMain = vscode.extensions.getExtension('vscode.markdown-language-features')?.packageJSON?.main || ''; - const linkProvider = new MdLinkProvider(parser, workspace, logger); - const referencesProvider = new MdReferencesProvider(parser, workspace, tocProvider, logger); - const symbolProvider = new MdDocumentSymbolProvider(tocProvider, logger); + const serverMain = `./server/${clientMain.indexOf('/dist/') !== -1 ? 'dist' : 'out'}/node/main`; + const serverModule = context.asAbsolutePath(serverMain); - return vscode.Disposable.from( - linkProvider, - referencesProvider, + // The debug options for the server + const debugOptions = { execArgv: ['--nolazy', '--inspect=' + (7000 + Math.round(Math.random() * 999))] }; - // Language features - registerDefinitionSupport(selector, referencesProvider), - registerDiagnosticSupport(selector, workspace, linkProvider, commandManager, referencesProvider, tocProvider, logger), - registerDocumentLinkSupport(selector, linkProvider), - registerDocumentSymbolSupport(selector, tocProvider, logger), - registerDropIntoEditorSupport(selector), - registerFindFileReferenceSupport(commandManager, referencesProvider), - registerFoldingSupport(selector, parser, tocProvider), - registerPasteSupport(selector), - registerPathCompletionSupport(selector, workspace, parser, linkProvider), - registerReferencesSupport(selector, referencesProvider), - registerRenameSupport(selector, workspace, referencesProvider, parser.slugifier), - registerSmartSelectSupport(selector, parser, tocProvider), - registerWorkspaceSymbolSupport(workspace, symbolProvider), - ); -} - -function registerMarkdownCommands( - commandManager: CommandManager, - previewManager: MarkdownPreviewManager, - telemetryReporter: TelemetryReporter, - cspArbiter: ContentSecurityPolicyArbiter, - engine: MarkdownItEngine, - tocProvider: MdTableOfContentsProvider, -): vscode.Disposable { - const previewSecuritySelector = new PreviewSecuritySelector(cspArbiter, previewManager); - - commandManager.register(new commands.ShowPreviewCommand(previewManager, telemetryReporter)); - commandManager.register(new commands.ShowPreviewToSideCommand(previewManager, telemetryReporter)); - commandManager.register(new commands.ShowLockedPreviewToSideCommand(previewManager, telemetryReporter)); - commandManager.register(new commands.ShowSourceCommand(previewManager)); - commandManager.register(new commands.RefreshPreviewCommand(previewManager, engine)); - commandManager.register(new commands.MoveCursorToPositionCommand()); - commandManager.register(new commands.ShowPreviewSecuritySelectorCommand(previewSecuritySelector, previewManager)); - commandManager.register(new commands.OpenDocumentLinkCommand(tocProvider)); - commandManager.register(new commands.ToggleLockCommand(previewManager)); - commandManager.register(new commands.RenderDocument(engine)); - commandManager.register(new commands.ReloadPlugins(previewManager, engine)); - return commandManager; + // If the extension is launch in debug mode the debug server options are use + // Otherwise the run options are used + const serverOptions: ServerOptions = { + run: { module: serverModule, transport: TransportKind.ipc }, + debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions } + }; + return startClient((id, name, clientOptions) => { + return new LanguageClient(id, name, serverOptions, clientOptions); + }, workspace, parser); } diff --git a/extensions/markdown-language-features/src/languageFeatures/definitions.ts b/extensions/markdown-language-features/src/languageFeatures/definitions.ts deleted file mode 100644 index d080dcaab1a..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/definitions.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import { ITextDocument } from '../types/textDocument'; -import { MdReferencesProvider } from './references'; - -export class MdVsCodeDefinitionProvider implements vscode.DefinitionProvider { - - constructor( - private readonly referencesProvider: MdReferencesProvider, - ) { } - - async provideDefinition(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise { - const allRefs = await this.referencesProvider.getReferencesAtPosition(document, position, token); - - return allRefs.find(ref => ref.kind === 'link' && ref.isDefinition)?.location; - } -} - -export function registerDefinitionSupport( - selector: vscode.DocumentSelector, - referencesProvider: MdReferencesProvider, -): vscode.Disposable { - return vscode.languages.registerDefinitionProvider(selector, new MdVsCodeDefinitionProvider(referencesProvider)); -} diff --git a/extensions/markdown-language-features/src/languageFeatures/diagnostics.ts b/extensions/markdown-language-features/src/languageFeatures/diagnostics.ts index f403b8ec7d6..6ae36b84aaf 100644 --- a/extensions/markdown-language-features/src/languageFeatures/diagnostics.ts +++ b/extensions/markdown-language-features/src/languageFeatures/diagnostics.ts @@ -3,609 +3,20 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as picomatch from 'picomatch'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { CommandManager } from '../commandManager'; -import { ILogger } from '../logging'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; -import { Delayer } from '../util/async'; -import { noopToken } from '../util/cancellation'; -import { Disposable } from '../util/dispose'; -import { isMarkdownFile, looksLikeMarkdownPath } from '../util/file'; -import { Limiter } from '../util/limiter'; -import { ResourceMap } from '../util/resourceMap'; -import { MdTableOfContentsWatcher } from '../util/tableOfContentsWatcher'; -import { IMdWorkspace } from '../workspace'; -import { InternalHref, LinkDefinitionSet, MdLink, MdLinkProvider, MdLinkSource } from './documentLinks'; -import { MdReferencesProvider, tryResolveLinkPath } from './references'; const localize = nls.loadMessageBundle(); -export interface DiagnosticConfiguration { - /** - * Fired when the configuration changes. - */ - readonly onDidChange: vscode.Event; - - getOptions(resource: vscode.Uri): DiagnosticOptions; +// Copied from markdown language service +export enum DiagnosticCode { + link_noSuchReferences = 'link.no-such-reference', + link_noSuchHeaderInOwnFile = 'link.no-such-header-in-own-file', + link_noSuchFile = 'link.no-such-file', + link_noSuchHeaderInFile = 'link.no-such-header-in-file', } -export enum DiagnosticLevel { - ignore = 'ignore', - warning = 'warning', - error = 'error', -} - -export interface DiagnosticOptions { - readonly enabled: boolean; - readonly validateReferences: DiagnosticLevel | undefined; - readonly validateFragmentLinks: DiagnosticLevel | undefined; - readonly validateFileLinks: DiagnosticLevel | undefined; - readonly validateMarkdownFileLinkFragments: DiagnosticLevel | undefined; - readonly ignoreLinks: readonly string[]; -} - -function toSeverity(level: DiagnosticLevel | undefined): vscode.DiagnosticSeverity | undefined { - switch (level) { - case DiagnosticLevel.error: return vscode.DiagnosticSeverity.Error; - case DiagnosticLevel.warning: return vscode.DiagnosticSeverity.Warning; - case DiagnosticLevel.ignore: return undefined; - case undefined: return undefined; - } -} - -class VSCodeDiagnosticConfiguration extends Disposable implements DiagnosticConfiguration { - - private readonly _onDidChange = this._register(new vscode.EventEmitter()); - public readonly onDidChange = this._onDidChange.event; - - constructor() { - super(); - - this._register(vscode.workspace.onDidChangeConfiguration(e => { - if ( - e.affectsConfiguration('markdown.experimental.validate.enabled') - || e.affectsConfiguration('markdown.experimental.validate.referenceLinks.enabled') - || e.affectsConfiguration('markdown.experimental.validate.fragmentLinks.enabled') - || e.affectsConfiguration('markdown.experimental.validate.fileLinks.enabled') - || e.affectsConfiguration('markdown.experimental.validate.fileLinks.markdownFragmentLinks') - || e.affectsConfiguration('markdown.experimental.validate.ignoreLinks') - ) { - this._onDidChange.fire(); - } - })); - } - - public getOptions(resource: vscode.Uri): DiagnosticOptions { - const config = vscode.workspace.getConfiguration('markdown', resource); - const validateFragmentLinks = config.get('experimental.validate.fragmentLinks.enabled'); - return { - enabled: config.get('experimental.validate.enabled', false), - validateReferences: config.get('experimental.validate.referenceLinks.enabled'), - validateFragmentLinks, - validateFileLinks: config.get('experimental.validate.fileLinks.enabled'), - validateMarkdownFileLinkFragments: config.get('markdown.experimental.validate.fileLinks.markdownFragmentLinks', validateFragmentLinks), - ignoreLinks: config.get('experimental.validate.ignoreLinks', []), - }; - } -} - -class InflightDiagnosticRequests { - - private readonly inFlightRequests = new ResourceMap<{ readonly cts: vscode.CancellationTokenSource }>(); - - public async trigger(resource: vscode.Uri, compute: (token: vscode.CancellationToken) => Promise): Promise { - this.cancel(resource); - - const cts = new vscode.CancellationTokenSource(); - const entry = { cts }; - this.inFlightRequests.set(resource, entry); - - try { - return await compute(cts.token); - } finally { - if (this.inFlightRequests.get(resource) === entry) { - this.inFlightRequests.delete(resource); - } - cts.dispose(); - } - } - - public cancel(resource: vscode.Uri) { - const existing = this.inFlightRequests.get(resource); - if (existing) { - existing.cts.cancel(); - this.inFlightRequests.delete(resource); - } - } - - public dispose() { - this.clear(); - } - - public clear() { - for (const { cts } of this.inFlightRequests.values()) { - cts.dispose(); - } - this.inFlightRequests.clear(); - } -} - -class LinkWatcher extends Disposable { - - private readonly _onDidChangeLinkedToFile = this._register(new vscode.EventEmitter>); - /** - * Event fired with a list of document uri when one of the links in the document changes - */ - public readonly onDidChangeLinkedToFile = this._onDidChangeLinkedToFile.event; - - private readonly _watchers = new ResourceMap<{ - /** - * Watcher for this link path - */ - readonly watcher: vscode.Disposable; - - /** - * List of documents that reference the link - */ - readonly documents: ResourceMap; - }>(); - - override dispose() { - super.dispose(); - - for (const entry of this._watchers.values()) { - entry.watcher.dispose(); - } - this._watchers.clear(); - } - - /** - * Set the known links in a markdown document, adding and removing file watchers as needed - */ - updateLinksForDocument(document: vscode.Uri, links: readonly MdLink[]) { - const linkedToResource = new Set( - links - .filter(link => link.href.kind === 'internal') - .map(link => (link.href as InternalHref).path)); - - // First decrement watcher counter for previous document state - for (const entry of this._watchers.values()) { - entry.documents.delete(document); - } - - // Then create/update watchers for new document state - for (const path of linkedToResource) { - let entry = this._watchers.get(path); - if (!entry) { - entry = { - watcher: this.startWatching(path), - documents: new ResourceMap(), - }; - this._watchers.set(path, entry); - } - - entry.documents.set(document, document); - } - - // Finally clean up watchers for links that are no longer are referenced anywhere - for (const [key, value] of this._watchers) { - if (value.documents.size === 0) { - value.watcher.dispose(); - this._watchers.delete(key); - } - } - } - - deleteDocument(resource: vscode.Uri) { - this.updateLinksForDocument(resource, []); - } - - private startWatching(path: vscode.Uri): vscode.Disposable { - const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(path, '*'), false, true, false); - const handler = (resource: vscode.Uri) => this.onLinkedResourceChanged(resource); - return vscode.Disposable.from( - watcher, - watcher.onDidDelete(handler), - watcher.onDidCreate(handler), - ); - } - - private onLinkedResourceChanged(resource: vscode.Uri) { - const entry = this._watchers.get(resource); - if (entry) { - this._onDidChangeLinkedToFile.fire(entry.documents.values()); - } - } -} - -class LinkDoesNotExistDiagnostic extends vscode.Diagnostic { - - public readonly link: string; - - constructor(range: vscode.Range, message: string, severity: vscode.DiagnosticSeverity, link: string) { - super(range, message, severity); - this.link = link; - } -} - -export abstract class DiagnosticReporter extends Disposable { - private readonly pending = new Set>(); - - public clear(): void { - this.pending.clear(); - } - - public abstract set(uri: vscode.Uri, diagnostics: readonly vscode.Diagnostic[]): void; - - public abstract delete(uri: vscode.Uri): void; - - public abstract isOpen(uri: vscode.Uri): boolean; - - public abstract getOpenDocuments(): ITextDocument[]; - - public addWorkItem(promise: Promise): Promise { - this.pending.add(promise); - promise.finally(() => this.pending.delete(promise)); - return promise; - } - - public async waitPendingWork(): Promise { - await Promise.all([...this.pending.values()]); - } -} - -export class DiagnosticCollectionReporter extends DiagnosticReporter { - - private readonly collection: vscode.DiagnosticCollection; - - constructor() { - super(); - this.collection = this._register(vscode.languages.createDiagnosticCollection('markdown')); - } - - public override clear(): void { - super.clear(); - this.collection.clear(); - } - - public set(uri: vscode.Uri, diagnostics: readonly vscode.Diagnostic[]): void { - this.collection.set(uri, this.isOpen(uri) ? diagnostics : []); - } - - public isOpen(uri: vscode.Uri): boolean { - const tabs = this.getTabResources(); - return tabs.has(uri); - } - - public delete(uri: vscode.Uri): void { - this.collection.delete(uri); - } - - public getOpenDocuments(): ITextDocument[] { - const tabs = this.getTabResources(); - return vscode.workspace.textDocuments.filter(doc => tabs.has(doc.uri)); - } - - private getTabResources(): ResourceMap { - const openedTabDocs = new ResourceMap(); - for (const group of vscode.window.tabGroups.all) { - for (const tab of group.tabs) { - if (tab.input instanceof vscode.TabInputText) { - openedTabDocs.set(tab.input.uri); - } - } - } - return openedTabDocs; - } -} - -export class DiagnosticManager extends Disposable { - - private readonly diagnosticDelayer: Delayer; - private readonly pendingDiagnostics = new Set(); - private readonly inFlightDiagnostics = this._register(new InflightDiagnosticRequests()); - - private readonly linkWatcher = this._register(new LinkWatcher()); - private readonly tableOfContentsWatcher: MdTableOfContentsWatcher; - - public readonly ready: Promise; - - constructor( - private readonly workspace: IMdWorkspace, - private readonly computer: DiagnosticComputer, - private readonly configuration: DiagnosticConfiguration, - private readonly reporter: DiagnosticReporter, - private readonly referencesProvider: MdReferencesProvider, - tocProvider: MdTableOfContentsProvider, - private readonly logger: ILogger, - delay = 300, - ) { - super(); - - this.diagnosticDelayer = this._register(new Delayer(delay)); - - this._register(this.configuration.onDidChange(() => { - this.rebuild(); - })); - - this._register(workspace.onDidCreateMarkdownDocument(doc => { - this.triggerDiagnostics(doc.uri); - // Links in other files may have become valid - this.triggerForReferencingFiles(doc.uri); - })); - - this._register(workspace.onDidChangeMarkdownDocument(doc => { - this.triggerDiagnostics(doc.uri); - })); - - this._register(workspace.onDidDeleteMarkdownDocument(uri => { - this.triggerForReferencingFiles(uri); - })); - - this._register(vscode.workspace.onDidCloseTextDocument(({ uri }) => { - this.pendingDiagnostics.delete(uri); - this.inFlightDiagnostics.cancel(uri); - this.linkWatcher.deleteDocument(uri); - this.reporter.delete(uri); - })); - - this._register(this.linkWatcher.onDidChangeLinkedToFile(changedDocuments => { - for (const resource of changedDocuments) { - const doc = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === resource.toString()); - if (doc && isMarkdownFile(doc)) { - this.triggerDiagnostics(doc.uri); - } - } - })); - - this.tableOfContentsWatcher = this._register(new MdTableOfContentsWatcher(workspace, tocProvider, delay / 2)); - this._register(this.tableOfContentsWatcher.onTocChanged(e => { - return this.triggerForReferencingFiles(e.uri); - })); - - this.ready = this.rebuild(); - } - - private triggerForReferencingFiles(uri: vscode.Uri): Promise { - return this.reporter.addWorkItem( - (async () => { - const triggered = new ResourceMap>(); - for (const ref of await this.referencesProvider.getReferencesToFileInDocs(uri, this.reporter.getOpenDocuments(), noopToken)) { - const file = ref.location.uri; - if (!triggered.has(file)) { - triggered.set(file, this.triggerDiagnostics(file)); - } - } - await Promise.all(triggered.values()); - })()); - } - - public override dispose() { - super.dispose(); - this.pendingDiagnostics.clear(); - } - - private async recomputeDiagnosticState(doc: ITextDocument, token: vscode.CancellationToken): Promise<{ diagnostics: readonly vscode.Diagnostic[]; links: readonly MdLink[]; config: DiagnosticOptions }> { - this.logger.verbose('DiagnosticManager', `recomputeDiagnosticState - ${doc.uri}`); - - const config = this.configuration.getOptions(doc.uri); - if (!config.enabled) { - return { diagnostics: [], links: [], config }; - } - return { ...await this.computer.getDiagnostics(doc, config, token), config }; - } - - private async recomputePendingDiagnostics(): Promise { - const pending = [...this.pendingDiagnostics]; - this.pendingDiagnostics.clear(); - - await Promise.all(pending.map(async resource => { - const doc = await this.workspace.getOrLoadMarkdownDocument(resource); - if (doc) { - await this.inFlightDiagnostics.trigger(doc.uri, async (token) => { - if (this.reporter.isOpen(doc.uri)) { - const state = await this.recomputeDiagnosticState(doc, token); - this.linkWatcher.updateLinksForDocument(doc.uri, state.config.enabled && state.config.validateFileLinks ? state.links : []); - this.reporter.set(doc.uri, state.diagnostics); - } else { - this.linkWatcher.deleteDocument(doc.uri); - this.reporter.delete(doc.uri); - } - }); - } - })); - } - - private rebuild(): Promise { - this.reporter.clear(); - this.pendingDiagnostics.clear(); - this.inFlightDiagnostics.clear(); - - return this.reporter.addWorkItem( - Promise.all(Array.from(this.reporter.getOpenDocuments(), doc => this.triggerDiagnostics(doc.uri))) - ); - } - - private async triggerDiagnostics(uri: vscode.Uri): Promise { - this.inFlightDiagnostics.cancel(uri); - - this.pendingDiagnostics.add(uri); - return this.reporter.addWorkItem( - this.diagnosticDelayer.trigger(() => this.recomputePendingDiagnostics()) - ); - } -} - -/** - * Map of file paths to markdown links to that file. - */ -class FileLinkMap { - - private readonly _filesToLinksMap = new ResourceMap<{ - readonly outgoingLinks: Array<{ - readonly source: MdLinkSource; - readonly fragment: string; - }>; - }>(); - - constructor(links: Iterable) { - for (const link of links) { - if (link.href.kind !== 'internal') { - continue; - } - - const existingFileEntry = this._filesToLinksMap.get(link.href.path); - const linkData = { source: link.source, fragment: link.href.fragment }; - if (existingFileEntry) { - existingFileEntry.outgoingLinks.push(linkData); - } else { - this._filesToLinksMap.set(link.href.path, { outgoingLinks: [linkData] }); - } - } - } - - public get size(): number { - return this._filesToLinksMap.size; - } - - public entries() { - return this._filesToLinksMap.entries(); - } -} - -export class DiagnosticComputer { - - constructor( - private readonly workspace: IMdWorkspace, - private readonly linkProvider: MdLinkProvider, - private readonly tocProvider: MdTableOfContentsProvider, - ) { } - - public async getDiagnostics(doc: ITextDocument, options: DiagnosticOptions, token: vscode.CancellationToken): Promise<{ readonly diagnostics: vscode.Diagnostic[]; readonly links: readonly MdLink[] }> { - const { links, definitions } = await this.linkProvider.getLinks(doc); - if (token.isCancellationRequested || !options.enabled) { - return { links, diagnostics: [] }; - } - - return { - links, - diagnostics: (await Promise.all([ - this.validateFileLinks(options, links, token), - Array.from(this.validateReferenceLinks(options, links, definitions)), - this.validateFragmentLinks(doc, options, links, token), - ])).flat() - }; - } - - private async validateFragmentLinks(doc: ITextDocument, options: DiagnosticOptions, links: readonly MdLink[], token: vscode.CancellationToken): Promise { - const severity = toSeverity(options.validateFragmentLinks); - if (typeof severity === 'undefined') { - return []; - } - - const toc = await this.tocProvider.getForDocument(doc); - if (token.isCancellationRequested) { - return []; - } - - const diagnostics: vscode.Diagnostic[] = []; - for (const link of links) { - if (link.href.kind === 'internal' - && link.source.hrefText.startsWith('#') - && link.href.path.toString() === doc.uri.toString() - && link.href.fragment - && !toc.lookup(link.href.fragment) - ) { - if (!this.isIgnoredLink(options, link.source.hrefText)) { - diagnostics.push(new LinkDoesNotExistDiagnostic( - link.source.hrefRange, - localize('invalidHeaderLink', 'No header found: \'{0}\'', link.href.fragment), - severity, - link.source.hrefText)); - } - } - } - - return diagnostics; - } - - private *validateReferenceLinks(options: DiagnosticOptions, links: readonly MdLink[], definitions: LinkDefinitionSet): Iterable { - const severity = toSeverity(options.validateReferences); - if (typeof severity === 'undefined') { - return []; - } - - for (const link of links) { - if (link.href.kind === 'reference' && !definitions.lookup(link.href.ref)) { - yield new vscode.Diagnostic( - link.source.hrefRange, - localize('invalidReferenceLink', 'No link definition found: \'{0}\'', link.href.ref), - severity); - } - } - } - - private async validateFileLinks(options: DiagnosticOptions, links: readonly MdLink[], token: vscode.CancellationToken): Promise { - const pathErrorSeverity = toSeverity(options.validateFileLinks); - if (typeof pathErrorSeverity === 'undefined') { - return []; - } - const fragmentErrorSeverity = toSeverity(typeof options.validateMarkdownFileLinkFragments === 'undefined' ? options.validateFragmentLinks : options.validateMarkdownFileLinkFragments); - - // We've already validated our own fragment links in `validateOwnHeaderLinks` - const linkSet = new FileLinkMap(links.filter(link => !link.source.hrefText.startsWith('#'))); - if (linkSet.size === 0) { - return []; - } - - const limiter = new Limiter(10); - - const diagnostics: vscode.Diagnostic[] = []; - await Promise.all( - Array.from(linkSet.entries()).map(([path, { outgoingLinks: links }]) => { - return limiter.queue(async () => { - if (token.isCancellationRequested) { - return; - } - - const resolvedHrefPath = await tryResolveLinkPath(path, this.workspace); - if (!resolvedHrefPath) { - const msg = localize('invalidPathLink', 'File does not exist at path: {0}', path.fsPath); - for (const link of links) { - if (!this.isIgnoredLink(options, link.source.pathText)) { - diagnostics.push(new LinkDoesNotExistDiagnostic(link.source.hrefRange, msg, pathErrorSeverity, link.source.pathText)); - } - } - } else if (typeof fragmentErrorSeverity !== 'undefined' && this.isMarkdownPath(resolvedHrefPath)) { - // Validate each of the links to headers in the file - const fragmentLinks = links.filter(x => x.fragment); - if (fragmentLinks.length) { - const toc = await this.tocProvider.get(resolvedHrefPath); - for (const link of fragmentLinks) { - if (!toc.lookup(link.fragment) && !this.isIgnoredLink(options, link.source.pathText) && !this.isIgnoredLink(options, link.source.hrefText)) { - const msg = localize('invalidLinkToHeaderInOtherFile', 'Header does not exist in file: {0}', link.fragment); - const range = link.source.fragmentRange?.with({ start: link.source.fragmentRange.start.translate(0, -1) }) ?? link.source.hrefRange; - diagnostics.push(new LinkDoesNotExistDiagnostic(range, msg, fragmentErrorSeverity, link.source.hrefText)); - } - } - } - } - }); - })); - return diagnostics; - } - - private isMarkdownPath(resolvedHrefPath: vscode.Uri) { - return this.workspace.hasMarkdownDocument(resolvedHrefPath) || looksLikeMarkdownPath(resolvedHrefPath); - } - - private isIgnoredLink(options: DiagnosticOptions, link: string): boolean { - return options.ignoreLinks.some(glob => picomatch.isMatch(link, glob)); - } -} class AddToIgnoreLinksQuickFixProvider implements vscode.CodeActionProvider { @@ -636,17 +47,26 @@ class AddToIgnoreLinksQuickFixProvider implements vscode.CodeActionProvider { const fixes: vscode.CodeAction[] = []; for (const diagnostic of context.diagnostics) { - if (diagnostic instanceof LinkDoesNotExistDiagnostic) { - const fix = new vscode.CodeAction( - localize('ignoreLinksQuickFix.title', "Exclude '{0}' from link validation.", diagnostic.link), - vscode.CodeActionKind.QuickFix); + switch (diagnostic.code) { + case DiagnosticCode.link_noSuchReferences: + case DiagnosticCode.link_noSuchHeaderInOwnFile: + case DiagnosticCode.link_noSuchFile: + case DiagnosticCode.link_noSuchHeaderInFile: { + const hrefText = (diagnostic as any).data?.hrefText; + if (hrefText) { + const fix = new vscode.CodeAction( + localize('ignoreLinksQuickFix.title', "Exclude '{0}' from link validation.", hrefText), + vscode.CodeActionKind.QuickFix); - fix.command = { - command: AddToIgnoreLinksQuickFixProvider._addToIgnoreLinksCommandId, - title: '', - arguments: [document.uri, diagnostic.link] - }; - fixes.push(fix); + fix.command = { + command: AddToIgnoreLinksQuickFixProvider._addToIgnoreLinksCommandId, + title: '', + arguments: [document.uri, hrefText], + }; + fixes.push(fix); + } + break; + } } } @@ -654,26 +74,10 @@ class AddToIgnoreLinksQuickFixProvider implements vscode.CodeActionProvider { } } + export function registerDiagnosticSupport( selector: vscode.DocumentSelector, - workspace: IMdWorkspace, - linkProvider: MdLinkProvider, commandManager: CommandManager, - referenceProvider: MdReferencesProvider, - tocProvider: MdTableOfContentsProvider, - logger: ILogger, ): vscode.Disposable { - const configuration = new VSCodeDiagnosticConfiguration(); - const manager = new DiagnosticManager( - workspace, - new DiagnosticComputer(workspace, linkProvider, tocProvider), - configuration, - new DiagnosticCollectionReporter(), - referenceProvider, - tocProvider, - logger); - return vscode.Disposable.from( - configuration, - manager, - AddToIgnoreLinksQuickFixProvider.register(selector, commandManager)); + return AddToIgnoreLinksQuickFixProvider.register(selector, commandManager); } diff --git a/extensions/markdown-language-features/src/languageFeatures/documentLinks.ts b/extensions/markdown-language-features/src/languageFeatures/documentLinks.ts deleted file mode 100644 index 4fe6320c6cc..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/documentLinks.ts +++ /dev/null @@ -1,606 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; -import * as uri from 'vscode-uri'; -import { OpenDocumentLinkCommand } from '../commands/openDocumentLink'; -import { ILogger } from '../logging'; -import { IMdParser } from '../markdownEngine'; -import { ITextDocument } from '../types/textDocument'; -import { coalesce } from '../util/arrays'; -import { noopToken } from '../util/cancellation'; -import { Disposable } from '../util/dispose'; -import { getUriForLinkWithKnownExternalScheme, isOfScheme, Schemes } from '../util/schemes'; -import { MdDocumentInfoCache } from '../util/workspaceCache'; -import { IMdWorkspace } from '../workspace'; - -const localize = nls.loadMessageBundle(); - -export interface ExternalHref { - readonly kind: 'external'; - readonly uri: vscode.Uri; -} - -export interface InternalHref { - readonly kind: 'internal'; - readonly path: vscode.Uri; - readonly fragment: string; -} - -export interface ReferenceHref { - readonly kind: 'reference'; - readonly ref: string; -} - -export type LinkHref = ExternalHref | InternalHref | ReferenceHref; - - -function resolveLink( - document: ITextDocument, - link: string, -): ExternalHref | InternalHref | undefined { - const cleanLink = stripAngleBrackets(link); - const externalSchemeUri = getUriForLinkWithKnownExternalScheme(cleanLink); - if (externalSchemeUri) { - // Normalize VS Code links to target currently running version - if (isOfScheme(Schemes.vscode, link) || isOfScheme(Schemes['vscode-insiders'], link)) { - return { kind: 'external', uri: vscode.Uri.parse(link).with({ scheme: vscode.env.uriScheme }) }; - } - return { kind: 'external', uri: externalSchemeUri }; - } - - if (/^[a-z\-][a-z\-]+:/i.test(cleanLink)) { - // Looks like a uri - return { kind: 'external', uri: vscode.Uri.parse(cleanLink) }; - } - - // Assume it must be an relative or absolute file path - // Use a fake scheme to avoid parse warnings - const tempUri = vscode.Uri.parse(`vscode-resource:${link}`); - - let resourceUri: vscode.Uri | undefined; - if (!tempUri.path) { - resourceUri = document.uri; - } else if (tempUri.path[0] === '/') { - const root = getWorkspaceFolder(document); - if (root) { - resourceUri = vscode.Uri.joinPath(root, tempUri.path); - } - } else { - if (document.uri.scheme === Schemes.untitled) { - const root = getWorkspaceFolder(document); - if (root) { - resourceUri = vscode.Uri.joinPath(root, tempUri.path); - } - } else { - const base = uri.Utils.dirname(document.uri); - resourceUri = vscode.Uri.joinPath(base, tempUri.path); - } - } - - if (!resourceUri) { - return undefined; - } - - // If we are in a notebook cell, resolve relative to notebook instead - if (resourceUri.scheme === Schemes.notebookCell) { - const notebook = vscode.workspace.notebookDocuments - .find(notebook => notebook.getCells().some(cell => cell.document === document)); - - if (notebook) { - resourceUri = resourceUri.with({ scheme: notebook.uri.scheme }); - } - } - - return { - kind: 'internal', - path: resourceUri.with({ fragment: '' }), - fragment: tempUri.fragment, - }; -} - -function getWorkspaceFolder(document: ITextDocument) { - return vscode.workspace.getWorkspaceFolder(document.uri)?.uri - || vscode.workspace.workspaceFolders?.[0]?.uri; -} - -export interface MdLinkSource { - /** - * The full range of the link. - */ - readonly range: vscode.Range; - - /** - * The file where the link is defined. - */ - readonly resource: vscode.Uri; - - /** - * The original text of the link destination in code. - */ - readonly hrefText: string; - - /** - * The original text of just the link's path in code. - */ - readonly pathText: string; - - /** - * The range of the path. - */ - readonly hrefRange: vscode.Range; - - /** - * The range of the fragment within the path. - */ - readonly fragmentRange: vscode.Range | undefined; -} - -export interface MdInlineLink { - readonly kind: 'link'; - readonly source: MdLinkSource; - readonly href: LinkHref; -} - -export interface MdLinkDefinition { - readonly kind: 'definition'; - readonly source: MdLinkSource; - readonly ref: { - readonly range: vscode.Range; - readonly text: string; - }; - readonly href: ExternalHref | InternalHref; -} - -export type MdLink = MdInlineLink | MdLinkDefinition; - -function extractDocumentLink( - document: ITextDocument, - pre: string, - rawLink: string, - matchIndex: number, - fullMatch: string, -): MdLink | undefined { - const isAngleBracketLink = rawLink.startsWith('<'); - const link = stripAngleBrackets(rawLink); - - let linkTarget: ExternalHref | InternalHref | undefined; - try { - linkTarget = resolveLink(document, link); - } catch { - return undefined; - } - if (!linkTarget) { - return undefined; - } - - const linkStart = document.positionAt(matchIndex); - const linkEnd = linkStart.translate(0, fullMatch.length); - const hrefStart = linkStart.translate(0, pre.length + (isAngleBracketLink ? 1 : 0)); - const hrefEnd = hrefStart.translate(0, link.length); - return { - kind: 'link', - href: linkTarget, - source: { - hrefText: link, - resource: document.uri, - range: new vscode.Range(linkStart, linkEnd), - hrefRange: new vscode.Range(hrefStart, hrefEnd), - ...getLinkSourceFragmentInfo(document, link, hrefStart, hrefEnd), - } - }; -} - -function getFragmentRange(text: string, start: vscode.Position, end: vscode.Position): vscode.Range | undefined { - const index = text.indexOf('#'); - if (index < 0) { - return undefined; - } - return new vscode.Range(start.translate({ characterDelta: index + 1 }), end); -} - -function getLinkSourceFragmentInfo(document: ITextDocument, link: string, linkStart: vscode.Position, linkEnd: vscode.Position): { fragmentRange: vscode.Range | undefined; pathText: string } { - const fragmentRange = getFragmentRange(link, linkStart, linkEnd); - return { - pathText: document.getText(new vscode.Range(linkStart, fragmentRange ? fragmentRange.start.translate(0, -1) : linkEnd)), - fragmentRange, - }; -} - -const angleBracketLinkRe = /^<(.*)>$/; - -/** - * Used to strip brackets from the markdown link - * - * will be transformed to http://example.com -*/ -function stripAngleBrackets(link: string) { - return link.replace(angleBracketLinkRe, '$1'); -} - -const r = String.raw; - -/** - * Matches `[text](link)` or `[text]()` - */ -const linkPattern = new RegExp( - // text - r`(\[` + // open prefix match --> - /**/r`(?:` + - /*****/r`[^\[\]\\]|` + // Non-bracket chars, or... - /*****/r`\\.|` + // Escaped char, or... - /*****/r`\[[^\[\]]*\]` + // Matched bracket pair - /**/r`)*` + - r`\]` + - - // Destination - r`\(\s*)` + // <-- close prefix match - /**/r`(` + - /*****/r`[^\s\(\)\<](?:[^\s\(\)]|\([^\s\(\)]*?\))*|` + // Link without whitespace, or... - /*****/r`<[^<>]+>` + // In angle brackets - /**/r`)` + - - // Title - /**/r`\s*(?:"[^"]*"|'[^']*'|\([^\(\)]*\))?\s*` + - r`\)`, - 'g'); - -/** -* Matches `[text][ref]` or `[shorthand]` -*/ -const referenceLinkPattern = /(^|[^\]\\])(?:(?:(\[((?:\\\]|[^\]])+)\]\[\s*?)([^\s\]]*?)\]|\[\s*?([^\s\\\]]*?)\])(?![\:\(]))/gm; - -/** - * Matches `` - */ -const autoLinkPattern = /\<(\w+:[^\>\s]+)\>/g; - -/** - * Matches `[text]: link` - */ -const definitionPattern = /^([\t ]*\[(?!\^)((?:\\\]|[^\]])+)\]:\s*)([^<]\S*|<[^>]+>)/gm; - -const inlineCodePattern = /(?:^|[^`])(`+)(?:.+?|.*?(?:(?:\r?\n).+?)*?)(?:\r?\n)?\1(?:$|[^`])/gm; - -class NoLinkRanges { - public static async compute(tokenizer: IMdParser, document: ITextDocument): Promise { - const tokens = await tokenizer.tokenize(document); - const multiline = tokens.filter(t => (t.type === 'code_block' || t.type === 'fence' || t.type === 'html_block') && !!t.map).map(t => t.map) as [number, number][]; - - const inlineRanges = new Map(); - const text = document.getText(); - for (const match of text.matchAll(inlineCodePattern)) { - const startOffset = match.index ?? 0; - const startPosition = document.positionAt(startOffset); - - const range = new vscode.Range(startPosition, document.positionAt(startOffset + match[0].length)); - for (let line = range.start.line; line <= range.end.line; ++line) { - let entry = inlineRanges.get(line); - if (!entry) { - entry = []; - inlineRanges.set(line, entry); - } - entry.push(range); - } - } - - return new NoLinkRanges(multiline, inlineRanges); - } - - private constructor( - /** - * code blocks and fences each represented by [line_start,line_end). - */ - public readonly multiline: ReadonlyArray<[number, number]>, - - /** - * Inline code spans where links should not be detected - */ - public readonly inline: Map - ) { } - - contains(position: vscode.Position): boolean { - return this.multiline.some(interval => position.line >= interval[0] && position.line < interval[1]) || - !!this.inline.get(position.line)?.some(inlineRange => inlineRange.contains(position)); - } - - concatInline(inlineRanges: Iterable): NoLinkRanges { - const newInline = new Map(this.inline); - for (const range of inlineRanges) { - for (let line = range.start.line; line <= range.end.line; ++line) { - let entry = newInline.get(line); - if (!entry) { - entry = []; - newInline.set(line, entry); - } - entry.push(range); - } - } - return new NoLinkRanges(this.multiline, newInline); - } -} - -/** - * Stateless object that extracts link information from markdown files. - */ -export class MdLinkComputer { - - constructor( - private readonly tokenizer: IMdParser, - ) { } - - public async getAllLinks(document: ITextDocument, token: vscode.CancellationToken): Promise { - const noLinkRanges = await NoLinkRanges.compute(this.tokenizer, document); - if (token.isCancellationRequested) { - return []; - } - - const inlineLinks = Array.from(this.getInlineLinks(document, noLinkRanges)); - return Array.from([ - ...inlineLinks, - ...this.getReferenceLinks(document, noLinkRanges.concatInline(inlineLinks.map(x => x.source.range))), - ...this.getLinkDefinitions(document, noLinkRanges), - ...this.getAutoLinks(document, noLinkRanges), - ]); - } - - private *getInlineLinks(document: ITextDocument, noLinkRanges: NoLinkRanges): Iterable { - const text = document.getText(); - for (const match of text.matchAll(linkPattern)) { - const matchLinkData = extractDocumentLink(document, match[1], match[2], match.index ?? 0, match[0]); - if (matchLinkData && !noLinkRanges.contains(matchLinkData.source.hrefRange.start)) { - yield matchLinkData; - - // Also check link destination for links - for (const innerMatch of match[1].matchAll(linkPattern)) { - const innerData = extractDocumentLink(document, innerMatch[1], innerMatch[2], (match.index ?? 0) + (innerMatch.index ?? 0), innerMatch[0]); - if (innerData) { - yield innerData; - } - } - } - } - } - - private *getAutoLinks(document: ITextDocument, noLinkRanges: NoLinkRanges): Iterable { - const text = document.getText(); - for (const match of text.matchAll(autoLinkPattern)) { - const linkOffset = (match.index ?? 0); - const linkStart = document.positionAt(linkOffset); - if (noLinkRanges.contains(linkStart)) { - continue; - } - - const link = match[1]; - const linkTarget = resolveLink(document, link); - if (!linkTarget) { - continue; - } - - const linkEnd = linkStart.translate(0, match[0].length); - const hrefStart = linkStart.translate(0, 1); - const hrefEnd = hrefStart.translate(0, link.length); - yield { - kind: 'link', - href: linkTarget, - source: { - hrefText: link, - resource: document.uri, - hrefRange: new vscode.Range(hrefStart, hrefEnd), - range: new vscode.Range(linkStart, linkEnd), - ...getLinkSourceFragmentInfo(document, link, hrefStart, hrefEnd), - } - }; - } - } - - private *getReferenceLinks(document: ITextDocument, noLinkRanges: NoLinkRanges): Iterable { - const text = document.getText(); - for (const match of text.matchAll(referenceLinkPattern)) { - const linkStart = document.positionAt(match.index ?? 0); - if (noLinkRanges.contains(linkStart)) { - continue; - } - - let hrefStart: vscode.Position; - let hrefEnd: vscode.Position; - let reference = match[4]; - if (reference === '') { // [ref][], - reference = match[3]; - const offset = ((match.index ?? 0) + match[1].length) + 1; - hrefStart = document.positionAt(offset); - hrefEnd = document.positionAt(offset + reference.length); - } else if (reference) { // [text][ref] - const pre = match[2]; - const offset = ((match.index ?? 0) + match[1].length) + pre.length; - hrefStart = document.positionAt(offset); - hrefEnd = document.positionAt(offset + reference.length); - } else if (match[5]) { // [ref] - reference = match[5]; - const offset = ((match.index ?? 0) + match[1].length) + 1; - hrefStart = document.positionAt(offset); - const line = document.lineAt(hrefStart.line); - // See if link looks like a checkbox - const checkboxMatch = line.text.match(/^\s*[\-\*]\s*\[x\]/i); - if (checkboxMatch && hrefStart.character <= checkboxMatch[0].length) { - continue; - } - hrefEnd = document.positionAt(offset + reference.length); - } else { - continue; - } - - const linkEnd = linkStart.translate(0, match[0].length); - yield { - kind: 'link', - source: { - hrefText: reference, - pathText: reference, - resource: document.uri, - range: new vscode.Range(linkStart, linkEnd), - hrefRange: new vscode.Range(hrefStart, hrefEnd), - fragmentRange: undefined, - }, - href: { - kind: 'reference', - ref: reference, - } - }; - } - } - - private *getLinkDefinitions(document: ITextDocument, noLinkRanges: NoLinkRanges): Iterable { - const text = document.getText(); - for (const match of text.matchAll(definitionPattern)) { - const offset = (match.index ?? 0); - const linkStart = document.positionAt(offset); - if (noLinkRanges.contains(linkStart)) { - continue; - } - - const pre = match[1]; - const reference = match[2]; - const rawLinkText = match[3].trim(); - const target = resolveLink(document, rawLinkText); - if (!target) { - continue; - } - - const isAngleBracketLink = angleBracketLinkRe.test(rawLinkText); - const linkText = stripAngleBrackets(rawLinkText); - const hrefStart = linkStart.translate(0, pre.length + (isAngleBracketLink ? 1 : 0)); - const hrefEnd = hrefStart.translate(0, linkText.length); - const hrefRange = new vscode.Range(hrefStart, hrefEnd); - - const refStart = linkStart.translate(0, 1); - const refRange = new vscode.Range(refStart, refStart.translate({ characterDelta: reference.length })); - const linkEnd = linkStart.translate(0, match[0].length); - yield { - kind: 'definition', - source: { - hrefText: linkText, - resource: document.uri, - range: new vscode.Range(linkStart, linkEnd), - hrefRange, - ...getLinkSourceFragmentInfo(document, rawLinkText, hrefStart, hrefEnd), - }, - ref: { text: reference, range: refRange }, - href: target, - }; - } - } -} - -interface MdDocumentLinks { - readonly links: readonly MdLink[]; - readonly definitions: LinkDefinitionSet; -} - -/** - * Stateful object which provides links for markdown files the workspace. - */ -export class MdLinkProvider extends Disposable { - - private readonly _linkCache: MdDocumentInfoCache; - - private readonly linkComputer: MdLinkComputer; - - constructor( - tokenizer: IMdParser, - workspace: IMdWorkspace, - logger: ILogger, - ) { - super(); - this.linkComputer = new MdLinkComputer(tokenizer); - this._linkCache = this._register(new MdDocumentInfoCache(workspace, async doc => { - logger.verbose('LinkProvider', `compute - ${doc.uri}`); - - const links = await this.linkComputer.getAllLinks(doc, noopToken); - return { - links, - definitions: new LinkDefinitionSet(links), - }; - })); - } - - public async getLinks(document: ITextDocument): Promise { - return this._linkCache.getForDocument(document); - } -} - -export class LinkDefinitionSet implements Iterable<[string, MdLinkDefinition]> { - private readonly _map = new Map(); - - constructor(links: Iterable) { - for (const link of links) { - if (link.kind === 'definition') { - this._map.set(link.ref.text, link); - } - } - } - - public [Symbol.iterator](): Iterator<[string, MdLinkDefinition]> { - return this._map.entries(); - } - - public lookup(ref: string): MdLinkDefinition | undefined { - return this._map.get(ref); - } -} - -export class MdVsCodeLinkProvider implements vscode.DocumentLinkProvider { - - constructor( - private readonly _linkProvider: MdLinkProvider, - ) { } - - public async provideDocumentLinks( - document: ITextDocument, - token: vscode.CancellationToken - ): Promise { - const { links, definitions } = await this._linkProvider.getLinks(document); - if (token.isCancellationRequested) { - return []; - } - - return coalesce(links.map(data => this.toValidDocumentLink(data, definitions))); - } - - private toValidDocumentLink(link: MdLink, definitionSet: LinkDefinitionSet): vscode.DocumentLink | undefined { - switch (link.href.kind) { - case 'external': { - return new vscode.DocumentLink(link.source.hrefRange, link.href.uri); - } - case 'internal': { - const uri = OpenDocumentLinkCommand.createCommandUri(link.source.resource, link.href.path, link.href.fragment); - const documentLink = new vscode.DocumentLink(link.source.hrefRange, uri); - documentLink.tooltip = localize('documentLink.tooltip', 'Follow link'); - return documentLink; - } - case 'reference': { - // We only render reference links in the editor if they are actually defined. - // This matches how reference links are rendered by markdown-it. - const def = definitionSet.lookup(link.href.ref); - if (def) { - const documentLink = new vscode.DocumentLink( - link.source.hrefRange, - vscode.Uri.parse(`command:_markdown.moveCursorToPosition?${encodeURIComponent(JSON.stringify([def.source.hrefRange.start.line, def.source.hrefRange.start.character]))}`)); - documentLink.tooltip = localize('documentLink.referenceTooltip', 'Go to link definition'); - return documentLink; - } else { - return undefined; - } - } - } - } -} - -export function registerDocumentLinkSupport( - selector: vscode.DocumentSelector, - linkProvider: MdLinkProvider, -): vscode.Disposable { - return vscode.languages.registerDocumentLinkProvider(selector, new MdVsCodeLinkProvider(linkProvider)); -} diff --git a/extensions/markdown-language-features/src/languageFeatures/documentSymbols.ts b/extensions/markdown-language-features/src/languageFeatures/documentSymbols.ts deleted file mode 100644 index a048180a4c6..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/documentSymbols.ts +++ /dev/null @@ -1,85 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { ILogger } from '../logging'; -import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; - -interface MarkdownSymbol { - readonly level: number; - readonly parent: MarkdownSymbol | undefined; - readonly children: vscode.DocumentSymbol[]; -} - -export class MdDocumentSymbolProvider implements vscode.DocumentSymbolProvider { - - constructor( - private readonly tocProvider: MdTableOfContentsProvider, - private readonly logger: ILogger, - ) { } - - public async provideDocumentSymbolInformation(document: ITextDocument): Promise { - this.logger.verbose('DocumentSymbolProvider', `provideDocumentSymbolInformation - ${document.uri}`); - const toc = await this.tocProvider.getForDocument(document); - return toc.entries.map(entry => this.toSymbolInformation(entry)); - } - - public async provideDocumentSymbols(document: ITextDocument): Promise { - const toc = await this.tocProvider.getForDocument(document); - const root: MarkdownSymbol = { - level: -Infinity, - children: [], - parent: undefined - }; - this.buildTree(root, toc.entries); - return root.children; - } - - private buildTree(parent: MarkdownSymbol, entries: readonly TocEntry[]) { - if (!entries.length) { - return; - } - - const entry = entries[0]; - const symbol = this.toDocumentSymbol(entry); - symbol.children = []; - - while (entry.level <= parent.level) { - parent = parent.parent!; - } - parent.children.push(symbol); - this.buildTree({ level: entry.level, children: symbol.children, parent }, entries.slice(1)); - } - - private toSymbolInformation(entry: TocEntry): vscode.SymbolInformation { - return new vscode.SymbolInformation( - this.getSymbolName(entry), - vscode.SymbolKind.String, - '', - entry.sectionLocation); - } - - private toDocumentSymbol(entry: TocEntry) { - return new vscode.DocumentSymbol( - this.getSymbolName(entry), - '', - vscode.SymbolKind.String, - entry.sectionLocation.range, - entry.sectionLocation.range); - } - - private getSymbolName(entry: TocEntry): string { - return '#'.repeat(entry.level) + ' ' + entry.text; - } -} - -export function registerDocumentSymbolSupport( - selector: vscode.DocumentSelector, - tocProvider: MdTableOfContentsProvider, - logger: ILogger, -): vscode.Disposable { - return vscode.languages.registerDocumentSymbolProvider(selector, new MdDocumentSymbolProvider(tocProvider, logger)); -} diff --git a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts index 0947e16840e..8dd01e67415 100644 --- a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts +++ b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts @@ -6,6 +6,7 @@ import * as path from 'path'; import * as vscode from 'vscode'; import * as URI from 'vscode-uri'; +import { Schemes } from '../util/schemes'; const imageFileExtensions = new Set([ '.bmp', @@ -24,8 +25,8 @@ const imageFileExtensions = new Set([ ]); export function registerDropIntoEditorSupport(selector: vscode.DocumentSelector) { - return vscode.languages.registerDocumentOnDropEditProvider(selector, new class implements vscode.DocumentOnDropEditProvider { - async provideDocumentOnDropEdits(document: vscode.TextDocument, _position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise { + return vscode.languages.registerDocumentDropEditProvider(selector, new class implements vscode.DocumentDropEditProvider { + async provideDocumentDropEdits(document: vscode.TextDocument, _position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise { const enabled = vscode.workspace.getConfiguration('markdown', document).get('editor.drop.enabled', true); if (!enabled) { return undefined; @@ -56,10 +57,12 @@ export async function tryGetUriListSnippet(document: vscode.TextDocument, dataTr return; } + const dir = getDocumentDir(document); + const snippet = new vscode.SnippetString(); uris.forEach((uri, i) => { - const mdPath = document.uri.scheme === uri.scheme - ? encodeURI(path.relative(URI.Utils.dirname(document.uri).fsPath, uri.fsPath).replace(/\\/g, '/')) + const mdPath = dir && dir.scheme === uri.scheme && dir.authority === uri.authority + ? encodeURI(path.relative(dir.fsPath, uri.fsPath).replace(/\\/g, '/')) : uri.toString(false); const ext = URI.Utils.extname(uri).toLowerCase(); @@ -74,3 +77,25 @@ export async function tryGetUriListSnippet(document: vscode.TextDocument, dataTr return snippet; } + +function getDocumentDir(document: vscode.TextDocument): vscode.Uri | undefined { + const docUri = getParentDocumentUri(document); + if (docUri.scheme === Schemes.untitled) { + return vscode.workspace.workspaceFolders?.[0]?.uri; + } + return URI.Utils.dirname(docUri); +} + +function getParentDocumentUri(document: vscode.TextDocument): vscode.Uri { + if (document.uri.scheme === Schemes.notebookCell) { + for (const notebook of vscode.workspace.notebookDocuments) { + for (const cell of notebook.getCells()) { + if (cell.document === document) { + return notebook.uri; + } + } + } + } + + return document.uri; +} diff --git a/extensions/markdown-language-features/src/languageFeatures/fileReferences.ts b/extensions/markdown-language-features/src/languageFeatures/fileReferences.ts index 4eea510d812..6d8b5eab079 100644 --- a/extensions/markdown-language-features/src/languageFeatures/fileReferences.ts +++ b/extensions/markdown-language-features/src/languageFeatures/fileReferences.ts @@ -4,9 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import { BaseLanguageClient } from 'vscode-languageclient'; +import type * as lsp from 'vscode-languageserver-types'; import * as nls from 'vscode-nls'; import { Command, CommandManager } from '../commandManager'; -import { MdReferencesProvider } from './references'; +import { getReferencesToFileInWorkspace } from '../protocol'; const localize = nls.loadMessageBundle(); @@ -16,7 +18,7 @@ export class FindFileReferencesCommand implements Command { public readonly id = 'markdown.findAllFileReferences'; constructor( - private readonly referencesProvider: MdReferencesProvider, + private readonly client: BaseLanguageClient, ) { } public async execute(resource?: vscode.Uri) { @@ -33,8 +35,9 @@ export class FindFileReferencesCommand implements Command { location: vscode.ProgressLocation.Window, title: localize('progress.title', "Finding file references") }, async (_progress, token) => { - const references = await this.referencesProvider.getReferencesToFileInWorkspace(resource!, token); - const locations = references.map(ref => ref.location); + const locations = (await this.client.sendRequest(getReferencesToFileInWorkspace, { uri: resource!.toString() }, token)).map(loc => { + return new vscode.Location(vscode.Uri.parse(loc.uri), convertRange(loc.range)); + }); const config = vscode.workspace.getConfiguration('references'); const existingSetting = config.inspect('preferredLocation'); @@ -49,9 +52,13 @@ export class FindFileReferencesCommand implements Command { } } +export function convertRange(range: lsp.Range): vscode.Range { + return new vscode.Range(range.start.line, range.start.character, range.end.line, range.end.character); +} + export function registerFindFileReferenceSupport( commandManager: CommandManager, - referencesProvider: MdReferencesProvider + client: BaseLanguageClient, ): vscode.Disposable { - return commandManager.register(new FindFileReferencesCommand(referencesProvider)); + return commandManager.register(new FindFileReferencesCommand(client)); } diff --git a/extensions/markdown-language-features/src/languageFeatures/folding.ts b/extensions/markdown-language-features/src/languageFeatures/folding.ts deleted file mode 100644 index f79df449b04..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/folding.ts +++ /dev/null @@ -1,122 +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 type Token = require('markdown-it/lib/token'); -import * as vscode from 'vscode'; -import { IMdParser } from '../markdownEngine'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; - -const rangeLimit = 5000; - -interface MarkdownItTokenWithMap extends Token { - map: [number, number]; -} - -export class MdFoldingProvider implements vscode.FoldingRangeProvider { - - constructor( - private readonly parser: IMdParser, - private readonly tocProvide: MdTableOfContentsProvider, - ) { } - - public async provideFoldingRanges( - document: ITextDocument, - _: vscode.FoldingContext, - _token: vscode.CancellationToken - ): Promise { - const foldables = await Promise.all([ - this.getRegions(document), - this.getHeaderFoldingRanges(document), - this.getBlockFoldingRanges(document) - ]); - return foldables.flat().slice(0, rangeLimit); - } - - private async getRegions(document: ITextDocument): Promise { - const tokens = await this.parser.tokenize(document); - const regionMarkers = tokens.filter(isRegionMarker) - .map(token => ({ line: token.map[0], isStart: isStartRegion(token.content) })); - - const nestingStack: { line: number; isStart: boolean }[] = []; - return regionMarkers - .map(marker => { - if (marker.isStart) { - nestingStack.push(marker); - } else if (nestingStack.length && nestingStack[nestingStack.length - 1].isStart) { - return new vscode.FoldingRange(nestingStack.pop()!.line, marker.line, vscode.FoldingRangeKind.Region); - } else { - // noop: invalid nesting (i.e. [end, start] or [start, end, end]) - } - return null; - }) - .filter((region: vscode.FoldingRange | null): region is vscode.FoldingRange => !!region); - } - - private async getHeaderFoldingRanges(document: ITextDocument): Promise { - const toc = await this.tocProvide.getForDocument(document); - return toc.entries.map(entry => { - let endLine = entry.sectionLocation.range.end.line; - if (document.lineAt(endLine).isEmptyOrWhitespace && endLine >= entry.line + 1) { - endLine = endLine - 1; - } - return new vscode.FoldingRange(entry.line, endLine); - }); - } - - private async getBlockFoldingRanges(document: ITextDocument): Promise { - const tokens = await this.parser.tokenize(document); - const multiLineListItems = tokens.filter(isFoldableToken); - return multiLineListItems.map(listItem => { - const start = listItem.map[0]; - let end = listItem.map[1] - 1; - if (document.lineAt(end).isEmptyOrWhitespace && end >= start + 1) { - end = end - 1; - } - return new vscode.FoldingRange(start, end, this.getFoldingRangeKind(listItem)); - }); - } - - private getFoldingRangeKind(listItem: Token): vscode.FoldingRangeKind | undefined { - return listItem.type === 'html_block' && listItem.content.startsWith('/.test(t); -const isEndRegion = (t: string) => /^\s*/.test(t); - -const isRegionMarker = (token: Token): token is MarkdownItTokenWithMap => - !!token.map && token.type === 'html_block' && (isStartRegion(token.content) || isEndRegion(token.content)); - -const isFoldableToken = (token: Token): token is MarkdownItTokenWithMap => { - if (!token.map) { - return false; - } - - switch (token.type) { - case 'fence': - case 'list_item_open': - return token.map[1] > token.map[0]; - - case 'html_block': - if (isRegionMarker(token)) { - return false; - } - return token.map[1] > token.map[0] + 1; - - default: - return false; - } -}; - -export function registerFoldingSupport( - selector: vscode.DocumentSelector, - parser: IMdParser, - tocProvider: MdTableOfContentsProvider, -): vscode.Disposable { - return vscode.languages.registerFoldingRangeProvider(selector, new MdFoldingProvider(parser, tocProvider)); -} diff --git a/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts b/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts new file mode 100644 index 00000000000..a34d6d03446 --- /dev/null +++ b/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts @@ -0,0 +1,253 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'path'; +import * as picomatch from 'picomatch'; +import * as vscode from 'vscode'; +import { BaseLanguageClient, TextDocumentEdit } from 'vscode-languageclient'; +import * as nls from 'vscode-nls'; +import { getEditForFileRenames } from '../protocol'; +import { Delayer } from '../util/async'; +import { noopToken } from '../util/cancellation'; +import { Disposable } from '../util/dispose'; +import { looksLikeMarkdownPath } from '../util/file'; +import { convertRange } from './fileReferences'; + +const localize = nls.loadMessageBundle(); + +const settingNames = Object.freeze({ + enabled: 'experimental.updateLinksOnFileMove.enabled', + externalFileGlobs: 'experimental.updateLinksOnFileMove.externalFileGlobs', + enableForDirectories: 'experimental.updateLinksOnFileMove.enableForDirectories', +}); + +const enum UpdateLinksOnFileMoveSetting { + Prompt = 'prompt', + Always = 'always', + Never = 'never', +} + +interface RenameAction { + readonly oldUri: vscode.Uri; + readonly newUri: vscode.Uri; +} + +class UpdateLinksOnFileRenameHandler extends Disposable { + + private readonly _delayer = new Delayer(50); + private readonly _pendingRenames = new Set(); + + public constructor( + private readonly client: BaseLanguageClient, + ) { + super(); + + this._register(vscode.workspace.onDidRenameFiles(async (e) => { + for (const { newUri, oldUri } of e.files) { + const config = vscode.workspace.getConfiguration('markdown', newUri); + if (!await this.shouldParticipateInLinkUpdate(config, newUri)) { + continue; + } + + this._pendingRenames.add({ newUri, oldUri }); + } + + if (this._pendingRenames.size) { + this._delayer.trigger(() => { + vscode.window.withProgress({ + location: vscode.ProgressLocation.Window, + title: localize('renameProgress.title', "Checking for Markdown links to update") + }, () => this.flushRenames()); + }); + } + })); + } + + private async flushRenames(): Promise { + const renames = Array.from(this._pendingRenames); + this._pendingRenames.clear(); + + const edit = new vscode.WorkspaceEdit(); + const resourcesBeingRenamed: vscode.Uri[] = []; + + for (const { oldUri, newUri } of renames) { + if (await this.withEditsForFileRename(edit, oldUri, newUri, noopToken)) { + resourcesBeingRenamed.push(newUri); + } + } + + if (edit.size) { + if (await this.confirmActionWithUser(resourcesBeingRenamed)) { + await vscode.workspace.applyEdit(edit); + } + } + } + + private async confirmActionWithUser(newResources: readonly vscode.Uri[]): Promise { + if (!newResources.length) { + return false; + } + + const config = vscode.workspace.getConfiguration('markdown', newResources[0]); + const setting = config.get(settingNames.enabled); + switch (setting) { + case UpdateLinksOnFileMoveSetting.Prompt: + return this.promptUser(newResources); + case UpdateLinksOnFileMoveSetting.Always: + return true; + case UpdateLinksOnFileMoveSetting.Never: + default: + return false; + } + } + private async shouldParticipateInLinkUpdate(config: vscode.WorkspaceConfiguration, newUri: vscode.Uri): Promise { + const setting = config.get(settingNames.enabled); + if (setting === UpdateLinksOnFileMoveSetting.Never) { + return false; + } + + if (looksLikeMarkdownPath(newUri)) { + return true; + } + + const externalGlob = config.get(settingNames.externalFileGlobs); + if (!!externalGlob && picomatch.isMatch(newUri.fsPath, externalGlob)) { + return true; + } + + const stat = await vscode.workspace.fs.stat(newUri); + if (stat.type === vscode.FileType.Directory) { + return config.get(settingNames.enableForDirectories, true); + } + + return false; + } + + private async promptUser(newResources: readonly vscode.Uri[]): Promise { + if (!newResources.length) { + return false; + } + + const enum Choice { + None = 0, + Accept = 1, + Reject = 2, + Always = 3, + Never = 4, + } + + interface Item extends vscode.MessageItem { + readonly choice: Choice; + } + + const response = await vscode.window.showInformationMessage( + newResources.length === 1 + ? localize('prompt', "Update Markdown links for '{0}'?", path.basename(newResources[0].fsPath)) + : this.getConfirmMessage(localize('promptMoreThanOne', "Update Markdown link for the following {0} files?", newResources.length), newResources), { + modal: true, + }, { + title: localize('reject.title', "No"), + choice: Choice.Reject, + isCloseAffordance: true, + }, { + title: localize('accept.title', "Yes"), + choice: Choice.Accept, + }, { + title: localize('always.title', "Always automatically update Markdown Links"), + choice: Choice.Always, + }, { + title: localize('never.title', "Never automatically update Markdown Links"), + choice: Choice.Never, + }); + + if (!response) { + return false; + } + + switch (response.choice) { + case Choice.Accept: { + return true; + } + case Choice.Reject: { + return false; + } + case Choice.Always: { + const config = vscode.workspace.getConfiguration('markdown', newResources[0]); + config.update( + settingNames.enabled, + UpdateLinksOnFileMoveSetting.Always, + this.getConfigTargetScope(config, settingNames.enabled)); + return true; + } + case Choice.Never: { + const config = vscode.workspace.getConfiguration('markdown', newResources[0]); + config.update( + settingNames.enabled, + UpdateLinksOnFileMoveSetting.Never, + this.getConfigTargetScope(config, settingNames.enabled)); + return false; + } + } + + return false; + } + + private async withEditsForFileRename( + workspaceEdit: vscode.WorkspaceEdit, + oldUri: vscode.Uri, + newUri: vscode.Uri, + token: vscode.CancellationToken, + ): Promise { + const edit = await this.client.sendRequest(getEditForFileRenames, [{ oldUri: oldUri.toString(), newUri: newUri.toString() }], token); + if (!edit.documentChanges?.length) { + return false; + } + + for (const change of edit.documentChanges as TextDocumentEdit[]) { + const uri = vscode.Uri.parse(change.textDocument.uri); + for (const edit of change.edits) { + workspaceEdit.replace(uri, convertRange(edit.range), edit.newText); + } + } + + return true; + } + + 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'); + } + + private getConfigTargetScope(config: vscode.WorkspaceConfiguration, settingsName: string): vscode.ConfigurationTarget { + const inspected = config.inspect(settingsName); + if (inspected?.workspaceFolderValue) { + return vscode.ConfigurationTarget.WorkspaceFolder; + } + + if (inspected?.workspaceValue) { + return vscode.ConfigurationTarget.Workspace; + } + + return vscode.ConfigurationTarget.Global; + } +} + +export function registerUpdateLinksOnRename(client: BaseLanguageClient) { + return new UpdateLinksOnFileRenameHandler(client); +} diff --git a/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts b/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts deleted file mode 100644 index 28f75b57444..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts +++ /dev/null @@ -1,367 +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 { dirname, resolve } from 'path'; -import * as vscode from 'vscode'; -import { IMdParser } from '../markdownEngine'; -import { TableOfContents } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; -import { resolveUriToMarkdownFile } from '../util/openDocumentLink'; -import { Schemes } from '../util/schemes'; -import { IMdWorkspace } from '../workspace'; -import { MdLinkProvider } from './documentLinks'; - -enum CompletionContextKind { - /** `[...](|)` */ - Link, - - /** `[...][|]` */ - ReferenceLink, - - /** `[]: |` */ - LinkDefinition, -} - -interface AnchorContext { - /** - * Link text before the `#`. - * - * For `[text](xy#z|abc)` this is `xy`. - */ - readonly beforeAnchor: string; - - /** - * Text of the anchor before the current position. - * - * For `[text](xy#z|abc)` this is `z`. - */ - readonly anchorPrefix: string; -} - -interface CompletionContext { - readonly kind: CompletionContextKind; - - /** - * Text of the link before the current position - * - * For `[text](xy#z|abc)` this is `xy#z`. - */ - readonly linkPrefix: string; - - /** - * Position of the start of the link. - * - * For `[text](xy#z|abc)` this is the position before `xy`. - */ - readonly linkTextStartPosition: vscode.Position; - - /** - * Text of the link after the current position. - * - * For `[text](xy#z|abc)` this is `abc`. - */ - readonly linkSuffix: string; - - /** - * Info if the link looks like it is for an anchor: `[](#header)` - */ - readonly anchorInfo?: AnchorContext; - - /** - * Indicates that the completion does not require encoding. - */ - readonly skipEncoding?: boolean; -} - -function tryDecodeUriComponent(str: string): string { - try { - return decodeURIComponent(str); - } catch { - return str; - } -} - -/** - * Adds path completions in markdown files by implementing {@link vscode.CompletionItemProvider}. - */ -export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProvider { - - constructor( - private readonly workspace: IMdWorkspace, - private readonly parser: IMdParser, - private readonly linkProvider: MdLinkProvider, - ) { } - - public async provideCompletionItems(document: ITextDocument, position: vscode.Position, _token: vscode.CancellationToken, _context: vscode.CompletionContext): Promise { - if (!this.arePathSuggestionEnabled(document)) { - return []; - } - - const context = this.getPathCompletionContext(document, position); - if (!context) { - return []; - } - - switch (context.kind) { - case CompletionContextKind.ReferenceLink: { - const items: vscode.CompletionItem[] = []; - for await (const item of this.provideReferenceSuggestions(document, position, context)) { - items.push(item); - } - return items; - } - - case CompletionContextKind.LinkDefinition: - case CompletionContextKind.Link: { - const items: vscode.CompletionItem[] = []; - - const isAnchorInCurrentDoc = context.anchorInfo && context.anchorInfo.beforeAnchor.length === 0; - - // Add anchor #links in current doc - if (context.linkPrefix.length === 0 || isAnchorInCurrentDoc) { - const insertRange = new vscode.Range(context.linkTextStartPosition, position); - for await (const item of this.provideHeaderSuggestions(document, position, context, insertRange)) { - items.push(item); - } - } - - if (!isAnchorInCurrentDoc) { - if (context.anchorInfo) { // Anchor to a different document - const rawUri = this.resolveReference(document, context.anchorInfo.beforeAnchor); - if (rawUri) { - const otherDoc = await resolveUriToMarkdownFile(this.workspace, rawUri); - if (otherDoc) { - const anchorStartPosition = position.translate({ characterDelta: -(context.anchorInfo.anchorPrefix.length + 1) }); - const range = new vscode.Range(anchorStartPosition, position); - for await (const item of this.provideHeaderSuggestions(otherDoc, position, context, range)) { - items.push(item); - } - } - } - } else { // Normal path suggestions - for await (const item of this.providePathSuggestions(document, position, context)) { - items.push(item); - } - } - } - - return items; - } - } - } - - private arePathSuggestionEnabled(document: ITextDocument): boolean { - const config = vscode.workspace.getConfiguration('markdown', document.uri); - return config.get('suggest.paths.enabled', true); - } - - /// [...](...| - private readonly linkStartPattern = /\[([^\]]*?)\]\(\s*(<[^\>\)]*|[^\s\(\)]*)$/; - - /// [...][...| - private readonly referenceLinkStartPattern = /\[([^\]]*?)\]\[\s*([^\s\(\)]*)$/; - - /// [id]: | - private readonly definitionPattern = /^\s*\[[\w\-]+\]:\s*([^\s]*)$/m; - - private getPathCompletionContext(document: ITextDocument, position: vscode.Position): CompletionContext | undefined { - const line = document.lineAt(position.line).text; - - const linePrefixText = line.slice(0, position.character); - const lineSuffixText = line.slice(position.character); - - const linkPrefixMatch = linePrefixText.match(this.linkStartPattern); - if (linkPrefixMatch) { - const isAngleBracketLink = linkPrefixMatch[2].startsWith('<'); - const prefix = linkPrefixMatch[2].slice(isAngleBracketLink ? 1 : 0); - if (this.refLooksLikeUrl(prefix)) { - return undefined; - } - - const suffix = lineSuffixText.match(/^[^\)\s][^\)\s\>]*/); - return { - kind: CompletionContextKind.Link, - linkPrefix: tryDecodeUriComponent(prefix), - linkTextStartPosition: position.translate({ characterDelta: -prefix.length }), - linkSuffix: suffix ? suffix[0] : '', - anchorInfo: this.getAnchorContext(prefix), - skipEncoding: isAngleBracketLink, - }; - } - - const definitionLinkPrefixMatch = linePrefixText.match(this.definitionPattern); - if (definitionLinkPrefixMatch) { - const prefix = definitionLinkPrefixMatch[1]; - if (this.refLooksLikeUrl(prefix)) { - return undefined; - } - - const suffix = lineSuffixText.match(/^[^\s]*/); - return { - kind: CompletionContextKind.LinkDefinition, - linkPrefix: tryDecodeUriComponent(prefix), - linkTextStartPosition: position.translate({ characterDelta: -prefix.length }), - linkSuffix: suffix ? suffix[0] : '', - anchorInfo: this.getAnchorContext(prefix), - }; - } - - const referenceLinkPrefixMatch = linePrefixText.match(this.referenceLinkStartPattern); - if (referenceLinkPrefixMatch) { - const prefix = referenceLinkPrefixMatch[2]; - const suffix = lineSuffixText.match(/^[^\]\s]*/); - return { - kind: CompletionContextKind.ReferenceLink, - linkPrefix: prefix, - linkTextStartPosition: position.translate({ characterDelta: -prefix.length }), - linkSuffix: suffix ? suffix[0] : '', - }; - } - - return undefined; - } - - /** - * Check if {@param ref} looks like a 'http:' style url. - */ - private refLooksLikeUrl(prefix: string): boolean { - return /^\s*[\w\d\-]+:/.test(prefix); - } - - private getAnchorContext(prefix: string): AnchorContext | undefined { - const anchorMatch = prefix.match(/^(.*)#([\w\d\-]*)$/); - if (!anchorMatch) { - return undefined; - } - return { - beforeAnchor: anchorMatch[1], - anchorPrefix: anchorMatch[2], - }; - } - - private async *provideReferenceSuggestions(document: ITextDocument, position: vscode.Position, context: CompletionContext): AsyncIterable { - const insertionRange = new vscode.Range(context.linkTextStartPosition, position); - const replacementRange = new vscode.Range(insertionRange.start, position.translate({ characterDelta: context.linkSuffix.length })); - - const { definitions } = await this.linkProvider.getLinks(document); - for (const [_, def] of definitions) { - yield { - kind: vscode.CompletionItemKind.Reference, - label: def.ref.text, - range: { - inserting: insertionRange, - replacing: replacementRange, - }, - }; - } - } - - private async *provideHeaderSuggestions(document: ITextDocument, position: vscode.Position, context: CompletionContext, insertionRange: vscode.Range): AsyncIterable { - const toc = await TableOfContents.createForDocumentOrNotebook(this.parser, document); - for (const entry of toc.entries) { - const replacementRange = new vscode.Range(insertionRange.start, position.translate({ characterDelta: context.linkSuffix.length })); - yield { - kind: vscode.CompletionItemKind.Reference, - label: '#' + decodeURIComponent(entry.slug.value), - range: { - inserting: insertionRange, - replacing: replacementRange, - }, - }; - } - } - - private async *providePathSuggestions(document: ITextDocument, position: vscode.Position, context: CompletionContext): AsyncIterable { - const valueBeforeLastSlash = context.linkPrefix.substring(0, context.linkPrefix.lastIndexOf('/') + 1); // keep the last slash - - const parentDir = this.resolveReference(document, valueBeforeLastSlash || '.'); - if (!parentDir) { - return; - } - - const pathSegmentStart = position.translate({ characterDelta: valueBeforeLastSlash.length - context.linkPrefix.length }); - const insertRange = new vscode.Range(pathSegmentStart, position); - - const pathSegmentEnd = position.translate({ characterDelta: context.linkSuffix.length }); - const replacementRange = new vscode.Range(pathSegmentStart, pathSegmentEnd); - - let dirInfo: [string, vscode.FileType][]; - try { - dirInfo = await this.workspace.readDirectory(parentDir); - } catch { - return; - } - - for (const [name, type] of dirInfo) { - // Exclude paths that start with `.` - if (name.startsWith('.')) { - continue; - } - - const isDir = type === vscode.FileType.Directory; - yield { - label: isDir ? name + '/' : name, - insertText: (context.skipEncoding ? name : encodeURIComponent(name)) + (isDir ? '/' : ''), - kind: isDir ? vscode.CompletionItemKind.Folder : vscode.CompletionItemKind.File, - range: { - inserting: insertRange, - replacing: replacementRange, - }, - command: isDir ? { command: 'editor.action.triggerSuggest', title: '' } : undefined, - }; - } - } - - private resolveReference(document: ITextDocument, ref: string): vscode.Uri | undefined { - const docUri = this.getFileUriOfTextDocument(document); - - if (ref.startsWith('/')) { - const workspaceFolder = vscode.workspace.getWorkspaceFolder(docUri); - if (workspaceFolder) { - return vscode.Uri.joinPath(workspaceFolder.uri, ref); - } else { - return this.resolvePath(docUri, ref.slice(1)); - } - } - - return this.resolvePath(docUri, ref); - } - - private resolvePath(root: vscode.Uri, ref: string): vscode.Uri | undefined { - try { - if (root.scheme === Schemes.file) { - return vscode.Uri.file(resolve(dirname(root.fsPath), ref)); - } else { - return root.with({ - path: resolve(dirname(root.path), ref), - }); - } - } catch { - return undefined; - } - } - - private getFileUriOfTextDocument(document: ITextDocument) { - if (document.uri.scheme === 'vscode-notebook-cell') { - const notebook = vscode.workspace.notebookDocuments - .find(notebook => notebook.getCells().some(cell => cell.document === document)); - - if (notebook) { - return notebook.uri; - } - } - - return document.uri; - } -} - -export function registerPathCompletionSupport( - selector: vscode.DocumentSelector, - workspace: IMdWorkspace, - parser: IMdParser, - linkProvider: MdLinkProvider, -): vscode.Disposable { - return vscode.languages.registerCompletionItemProvider(selector, new MdVsCodePathCompletionProvider(workspace, parser, linkProvider), '.', '/', '#'); -} diff --git a/extensions/markdown-language-features/src/languageFeatures/references.ts b/extensions/markdown-language-features/src/languageFeatures/references.ts deleted file mode 100644 index 51b7e7b92a1..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/references.ts +++ /dev/null @@ -1,353 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import * as uri from 'vscode-uri'; -import { ILogger } from '../logging'; -import { IMdParser } from '../markdownEngine'; -import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; -import { noopToken } from '../util/cancellation'; -import { Disposable } from '../util/dispose'; -import { looksLikeMarkdownPath } from '../util/file'; -import { MdWorkspaceInfoCache } from '../util/workspaceCache'; -import { IMdWorkspace } from '../workspace'; -import { InternalHref, MdLink, MdLinkComputer } from './documentLinks'; - - -/** - * A link in a markdown file. - */ -export interface MdLinkReference { - readonly kind: 'link'; - readonly isTriggerLocation: boolean; - readonly isDefinition: boolean; - readonly location: vscode.Location; - - readonly link: MdLink; -} - -/** - * A header in a markdown file. - */ -export interface MdHeaderReference { - readonly kind: 'header'; - - readonly isTriggerLocation: boolean; - readonly isDefinition: boolean; - - /** - * The range of the header. - * - * In `# a b c #` this would be the range of `# a b c #` - */ - readonly location: vscode.Location; - - /** - * The text of the header. - * - * In `# a b c #` this would be `a b c` - */ - readonly headerText: string; - - /** - * The range of the header text itself. - * - * In `# a b c #` this would be the range of `a b c` - */ - readonly headerTextLocation: vscode.Location; -} - -export type MdReference = MdLinkReference | MdHeaderReference; - -/** - * Stateful object that computes references for markdown files. - */ -export class MdReferencesProvider extends Disposable { - - private readonly _linkCache: MdWorkspaceInfoCache; - - public constructor( - private readonly parser: IMdParser, - private readonly workspace: IMdWorkspace, - private readonly tocProvider: MdTableOfContentsProvider, - private readonly logger: ILogger, - ) { - super(); - - const linkComputer = new MdLinkComputer(parser); - this._linkCache = this._register(new MdWorkspaceInfoCache(workspace, doc => linkComputer.getAllLinks(doc, noopToken))); - } - - public async getReferencesAtPosition(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise { - this.logger.verbose('ReferencesProvider', `getReferencesAtPosition: ${document.uri}`); - - const toc = await this.tocProvider.getForDocument(document); - if (token.isCancellationRequested) { - return []; - } - - const header = toc.entries.find(entry => entry.line === position.line); - if (header) { - return this.getReferencesToHeader(document, header); - } else { - return this.getReferencesToLinkAtPosition(document, position, token); - } - } - - public async getReferencesToFileInWorkspace(resource: vscode.Uri, token: vscode.CancellationToken): Promise { - this.logger.verbose('ReferencesProvider', `getAllReferencesToFileInWorkspace: ${resource}`); - - const allLinksInWorkspace = (await this._linkCache.values()).flat(); - if (token.isCancellationRequested) { - return []; - } - - return Array.from(this.findLinksToFile(resource, allLinksInWorkspace, undefined)); - } - - public async getReferencesToFileInDocs(resource: vscode.Uri, otherDocs: readonly ITextDocument[], token: vscode.CancellationToken): Promise { - this.logger.verbose('ReferencesProvider', `getAllReferencesToFileInFiles: ${resource}`); - - const links = (await this._linkCache.getForDocs(otherDocs)).flat(); - if (token.isCancellationRequested) { - return []; - } - - return Array.from(this.findLinksToFile(resource, links, undefined)); - } - - private async getReferencesToHeader(document: ITextDocument, header: TocEntry): Promise { - const links = (await this._linkCache.values()).flat(); - - const references: MdReference[] = []; - - references.push({ - kind: 'header', - isTriggerLocation: true, - isDefinition: true, - location: header.headerLocation, - headerText: header.text, - headerTextLocation: header.headerTextLocation - }); - - for (const link of links) { - if (link.href.kind === 'internal' - && this.looksLikeLinkToDoc(link.href, document.uri) - && this.parser.slugifier.fromHeading(link.href.fragment).value === header.slug.value - ) { - references.push({ - kind: 'link', - isTriggerLocation: false, - isDefinition: false, - link, - location: new vscode.Location(link.source.resource, link.source.hrefRange), - }); - } - } - - return references; - } - - private async getReferencesToLinkAtPosition(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise { - const docLinks = (await this._linkCache.getForDocs([document]))[0]; - - for (const link of docLinks) { - if (link.kind === 'definition') { - // We could be in either the ref name or the definition - if (link.ref.range.contains(position)) { - return Array.from(this.getReferencesToLinkReference(docLinks, link.ref.text, { resource: document.uri, range: link.ref.range })); - } else if (link.source.hrefRange.contains(position)) { - return this.getReferencesToLink(link, position, token); - } - } else { - if (link.source.hrefRange.contains(position)) { - return this.getReferencesToLink(link, position, token); - } - } - } - - return []; - } - - private async getReferencesToLink(sourceLink: MdLink, triggerPosition: vscode.Position, token: vscode.CancellationToken): Promise { - const allLinksInWorkspace = (await this._linkCache.values()).flat(); - if (token.isCancellationRequested) { - return []; - } - - if (sourceLink.href.kind === 'reference') { - return Array.from(this.getReferencesToLinkReference(allLinksInWorkspace, sourceLink.href.ref, { resource: sourceLink.source.resource, range: sourceLink.source.hrefRange })); - } - - if (sourceLink.href.kind === 'external') { - const references: MdReference[] = []; - - for (const link of allLinksInWorkspace) { - if (link.href.kind === 'external' && link.href.uri.toString() === sourceLink.href.uri.toString()) { - const isTriggerLocation = sourceLink.source.resource.fsPath === link.source.resource.fsPath && sourceLink.source.hrefRange.isEqual(link.source.hrefRange); - references.push({ - kind: 'link', - isTriggerLocation, - isDefinition: false, - link, - location: new vscode.Location(link.source.resource, link.source.hrefRange), - }); - } - } - return references; - } - - const resolvedResource = await tryResolveLinkPath(sourceLink.href.path, this.workspace); - if (token.isCancellationRequested) { - return []; - } - - const references: MdReference[] = []; - - if (resolvedResource && this.isMarkdownPath(resolvedResource) && sourceLink.href.fragment && sourceLink.source.fragmentRange?.contains(triggerPosition)) { - const toc = await this.tocProvider.get(resolvedResource); - const entry = toc.lookup(sourceLink.href.fragment); - if (entry) { - references.push({ - kind: 'header', - isTriggerLocation: false, - isDefinition: true, - location: entry.headerLocation, - headerText: entry.text, - headerTextLocation: entry.headerTextLocation - }); - } - - for (const link of allLinksInWorkspace) { - if (link.href.kind !== 'internal' || !this.looksLikeLinkToDoc(link.href, resolvedResource)) { - continue; - } - - if (this.parser.slugifier.fromHeading(link.href.fragment).equals(this.parser.slugifier.fromHeading(sourceLink.href.fragment))) { - const isTriggerLocation = sourceLink.source.resource.fsPath === link.source.resource.fsPath && sourceLink.source.hrefRange.isEqual(link.source.hrefRange); - references.push({ - kind: 'link', - isTriggerLocation, - isDefinition: false, - link, - location: new vscode.Location(link.source.resource, link.source.hrefRange), - }); - } - } - } else { // Triggered on a link without a fragment so we only require matching the file and ignore fragments - references.push(...this.findLinksToFile(resolvedResource ?? sourceLink.href.path, allLinksInWorkspace, sourceLink)); - } - - return references; - } - - private isMarkdownPath(resolvedHrefPath: vscode.Uri) { - return this.workspace.hasMarkdownDocument(resolvedHrefPath) || looksLikeMarkdownPath(resolvedHrefPath); - } - - private looksLikeLinkToDoc(href: InternalHref, targetDoc: vscode.Uri) { - return href.path.fsPath === targetDoc.fsPath - || uri.Utils.extname(href.path) === '' && href.path.with({ path: href.path.path + '.md' }).fsPath === targetDoc.fsPath; - } - - private *findLinksToFile(resource: vscode.Uri, links: readonly MdLink[], sourceLink: MdLink | undefined): Iterable { - for (const link of links) { - if (link.href.kind !== 'internal' || !this.looksLikeLinkToDoc(link.href, resource)) { - continue; - } - - // Exclude cases where the file is implicitly referencing itself - if (link.source.hrefText.startsWith('#') && link.source.resource.fsPath === resource.fsPath) { - continue; - } - - const isTriggerLocation = !!sourceLink && sourceLink.source.resource.fsPath === link.source.resource.fsPath && sourceLink.source.hrefRange.isEqual(link.source.hrefRange); - const pathRange = this.getPathRange(link); - yield { - kind: 'link', - isTriggerLocation, - isDefinition: false, - link, - location: new vscode.Location(link.source.resource, pathRange), - }; - } - } - - private *getReferencesToLinkReference(allLinks: Iterable, refToFind: string, from: { resource: vscode.Uri; range: vscode.Range }): Iterable { - for (const link of allLinks) { - let ref: string; - if (link.kind === 'definition') { - ref = link.ref.text; - } else if (link.href.kind === 'reference') { - ref = link.href.ref; - } else { - continue; - } - - if (ref === refToFind && link.source.resource.fsPath === from.resource.fsPath) { - const isTriggerLocation = from.resource.fsPath === link.source.resource.fsPath && ( - (link.href.kind === 'reference' && from.range.isEqual(link.source.hrefRange)) || (link.kind === 'definition' && from.range.isEqual(link.ref.range))); - - const pathRange = this.getPathRange(link); - yield { - kind: 'link', - isTriggerLocation, - isDefinition: link.kind === 'definition', - link, - location: new vscode.Location(from.resource, pathRange), - }; - } - } - } - - /** - * Get just the range of the file path, dropping the fragment - */ - private getPathRange(link: MdLink): vscode.Range { - return link.source.fragmentRange - ? link.source.hrefRange.with(undefined, link.source.fragmentRange.start.translate(0, -1)) - : link.source.hrefRange; - } -} - -/** - * Implements {@link vscode.ReferenceProvider} for markdown documents. - */ -export class MdVsCodeReferencesProvider implements vscode.ReferenceProvider { - - public constructor( - private readonly referencesProvider: MdReferencesProvider - ) { } - - async provideReferences(document: ITextDocument, position: vscode.Position, context: vscode.ReferenceContext, token: vscode.CancellationToken): Promise { - const allRefs = await this.referencesProvider.getReferencesAtPosition(document, position, token); - return allRefs - .filter(ref => context.includeDeclaration || !ref.isDefinition) - .map(ref => ref.location); - } -} - -export function registerReferencesSupport( - selector: vscode.DocumentSelector, - referencesProvider: MdReferencesProvider, -): vscode.Disposable { - return vscode.languages.registerReferenceProvider(selector, new MdVsCodeReferencesProvider(referencesProvider)); -} - -export async function tryResolveLinkPath(originalUri: vscode.Uri, workspace: IMdWorkspace): Promise { - if (await workspace.pathExists(originalUri)) { - return originalUri; - } - - // We don't think the file exists. If it doesn't already have an extension, try tacking on a `.md` and using that instead - if (uri.Utils.extname(originalUri) === '') { - const dotMdResource = originalUri.with({ path: originalUri.path + '.md' }); - if (await workspace.pathExists(dotMdResource)) { - return dotMdResource; - } - } - - return undefined; -} diff --git a/extensions/markdown-language-features/src/languageFeatures/rename.ts b/extensions/markdown-language-features/src/languageFeatures/rename.ts deleted file mode 100644 index 44870e33ff1..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/rename.ts +++ /dev/null @@ -1,281 +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 path from 'path'; -import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; -import * as URI from 'vscode-uri'; -import { Slugifier } from '../slugify'; -import { ITextDocument } from '../types/textDocument'; -import { Disposable } from '../util/dispose'; -import { resolveDocumentLink } from '../util/openDocumentLink'; -import { IMdWorkspace } from '../workspace'; -import { InternalHref } from './documentLinks'; -import { MdHeaderReference, MdLinkReference, MdReference, MdReferencesProvider, tryResolveLinkPath } from './references'; - -const localize = nls.loadMessageBundle(); - - -export interface MdReferencesResponse { - references: MdReference[]; - triggerRef: MdReference; -} - -interface MdFileRenameEdit { - readonly from: vscode.Uri; - readonly to: vscode.Uri; -} - -/** - * Type with additional metadata about the edits for testing - * - * This is needed since `vscode.WorkspaceEdit` does not expose info on file renames. - */ -export interface MdWorkspaceEdit { - readonly edit: vscode.WorkspaceEdit; - - readonly fileRenames?: ReadonlyArray; -} - -function tryDecodeUri(str: string): string { - try { - return decodeURI(str); - } catch { - return str; - } -} - -export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameProvider { - - private cachedRefs?: { - readonly resource: vscode.Uri; - readonly version: number; - readonly position: vscode.Position; - readonly triggerRef: MdReference; - readonly references: MdReference[]; - } | undefined; - - private readonly renameNotSupportedText = localize('invalidRenameLocation', "Rename not supported at location"); - - public constructor( - private readonly workspace: IMdWorkspace, - private readonly referencesProvider: MdReferencesProvider, - private readonly slugifier: Slugifier, - ) { - super(); - } - - public async prepareRename(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise { - const allRefsInfo = await this.getAllReferences(document, position, token); - if (token.isCancellationRequested) { - return undefined; - } - - if (!allRefsInfo || !allRefsInfo.references.length) { - throw new Error(this.renameNotSupportedText); - } - - const triggerRef = allRefsInfo.triggerRef; - switch (triggerRef.kind) { - case 'header': { - return { range: triggerRef.headerTextLocation.range, placeholder: triggerRef.headerText }; - } - case 'link': { - if (triggerRef.link.kind === 'definition') { - // We may have been triggered on the ref or the definition itself - if (triggerRef.link.ref.range.contains(position)) { - return { range: triggerRef.link.ref.range, placeholder: triggerRef.link.ref.text }; - } - } - - if (triggerRef.link.href.kind === 'external') { - return { range: triggerRef.link.source.hrefRange, placeholder: document.getText(triggerRef.link.source.hrefRange) }; - } - - // See if we are renaming the fragment or the path - const { fragmentRange } = triggerRef.link.source; - if (fragmentRange?.contains(position)) { - const declaration = this.findHeaderDeclaration(allRefsInfo.references); - if (declaration) { - return { range: fragmentRange, placeholder: declaration.headerText }; - } - return { range: fragmentRange, placeholder: document.getText(fragmentRange) }; - } - - const range = this.getFilePathRange(triggerRef); - if (!range) { - throw new Error(this.renameNotSupportedText); - } - return { range, placeholder: tryDecodeUri(document.getText(range)) }; - } - } - } - - private getFilePathRange(ref: MdLinkReference): vscode.Range { - if (ref.link.source.fragmentRange) { - return ref.link.source.hrefRange.with(undefined, ref.link.source.fragmentRange.start.translate(0, -1)); - } - return ref.link.source.hrefRange; - } - - private findHeaderDeclaration(references: readonly MdReference[]): MdHeaderReference | undefined { - return references.find(ref => ref.isDefinition && ref.kind === 'header') as MdHeaderReference | undefined; - } - - public async provideRenameEdits(document: ITextDocument, position: vscode.Position, newName: string, token: vscode.CancellationToken): Promise { - return (await this.provideRenameEditsImpl(document, position, newName, token))?.edit; - } - - public async provideRenameEditsImpl(document: ITextDocument, position: vscode.Position, newName: string, token: vscode.CancellationToken): Promise { - const allRefsInfo = await this.getAllReferences(document, position, token); - if (token.isCancellationRequested || !allRefsInfo || !allRefsInfo.references.length) { - return undefined; - } - - const triggerRef = allRefsInfo.triggerRef; - - if (triggerRef.kind === 'link' && ( - (triggerRef.link.kind === 'definition' && triggerRef.link.ref.range.contains(position)) || triggerRef.link.href.kind === 'reference' - )) { - return this.renameReferenceLinks(allRefsInfo, newName); - } else if (triggerRef.kind === 'link' && triggerRef.link.href.kind === 'external') { - return this.renameExternalLink(allRefsInfo, newName); - } else if (triggerRef.kind === 'header' || (triggerRef.kind === 'link' && triggerRef.link.source.fragmentRange?.contains(position) && (triggerRef.link.kind === 'definition' || triggerRef.link.kind === 'link' && triggerRef.link.href.kind === 'internal'))) { - return this.renameFragment(allRefsInfo, newName); - } else if (triggerRef.kind === 'link' && !triggerRef.link.source.fragmentRange?.contains(position) && (triggerRef.link.kind === 'link' || triggerRef.link.kind === 'definition') && triggerRef.link.href.kind === 'internal') { - return this.renameFilePath(triggerRef.link.source.resource, triggerRef.link.href, allRefsInfo, newName); - } - - return undefined; - } - - private async renameFilePath(triggerDocument: vscode.Uri, triggerHref: InternalHref, allRefsInfo: MdReferencesResponse, newName: string): Promise { - const edit = new vscode.WorkspaceEdit(); - const fileRenames: MdFileRenameEdit[] = []; - - const targetUri = await tryResolveLinkPath(triggerHref.path, this.workspace) ?? triggerHref.path; - - const rawNewFilePath = resolveDocumentLink(newName, triggerDocument); - let resolvedNewFilePath = rawNewFilePath; - if (!URI.Utils.extname(resolvedNewFilePath)) { - // If the newly entered path doesn't have a file extension but the original file did - // tack on a .md file extension - if (URI.Utils.extname(targetUri)) { - resolvedNewFilePath = resolvedNewFilePath.with({ - path: resolvedNewFilePath.path + '.md' - }); - } - } - - // First rename the file - if (await this.workspace.pathExists(targetUri)) { - fileRenames.push({ from: targetUri, to: resolvedNewFilePath }); - edit.renameFile(targetUri, resolvedNewFilePath); - } - - // Then update all refs to it - for (const ref of allRefsInfo.references) { - if (ref.kind === 'link') { - // Try to preserve style of existing links - let newPath: string; - if (ref.link.source.hrefText.startsWith('/')) { - const root = resolveDocumentLink('/', ref.link.source.resource); - newPath = '/' + path.relative(root.toString(true), rawNewFilePath.toString(true)); - } else { - const rootDir = URI.Utils.dirname(ref.link.source.resource); - if (rootDir.scheme === rawNewFilePath.scheme && rootDir.scheme !== 'untitled') { - newPath = path.relative(rootDir.toString(true), rawNewFilePath.toString(true)); - if (newName.startsWith('./') && !newPath.startsWith('../') || newName.startsWith('.\\') && !newPath.startsWith('..\\')) { - newPath = './' + newPath; - } - } else { - newPath = newName; - } - } - edit.replace(ref.link.source.resource, this.getFilePathRange(ref), encodeURI(newPath.replace(/\\/g, '/'))); - } - } - - return { edit, fileRenames }; - } - - private renameFragment(allRefsInfo: MdReferencesResponse, newName: string): MdWorkspaceEdit { - const slug = this.slugifier.fromHeading(newName).value; - - const edit = new vscode.WorkspaceEdit(); - for (const ref of allRefsInfo.references) { - switch (ref.kind) { - case 'header': - edit.replace(ref.location.uri, ref.headerTextLocation.range, newName); - break; - - case 'link': - edit.replace(ref.link.source.resource, ref.link.source.fragmentRange ?? ref.location.range, !ref.link.source.fragmentRange || ref.link.href.kind === 'external' ? newName : slug); - break; - } - } - return { edit }; - } - - private renameExternalLink(allRefsInfo: MdReferencesResponse, newName: string): MdWorkspaceEdit { - const edit = new vscode.WorkspaceEdit(); - for (const ref of allRefsInfo.references) { - if (ref.kind === 'link') { - edit.replace(ref.link.source.resource, ref.location.range, newName); - } - } - return { edit }; - } - - private renameReferenceLinks(allRefsInfo: MdReferencesResponse, newName: string): MdWorkspaceEdit { - const edit = new vscode.WorkspaceEdit(); - for (const ref of allRefsInfo.references) { - if (ref.kind === 'link') { - if (ref.link.kind === 'definition') { - edit.replace(ref.link.source.resource, ref.link.ref.range, newName); - } else { - edit.replace(ref.link.source.resource, ref.link.source.fragmentRange ?? ref.location.range, newName); - } - } - } - return { edit }; - } - - private async getAllReferences(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise { - const version = document.version; - - if (this.cachedRefs - && this.cachedRefs.resource.fsPath === document.uri.fsPath - && this.cachedRefs.version === document.version - && this.cachedRefs.position.isEqual(position) - ) { - return this.cachedRefs; - } - - const references = await this.referencesProvider.getReferencesAtPosition(document, position, token); - const triggerRef = references.find(ref => ref.isTriggerLocation); - if (!triggerRef) { - return undefined; - } - - this.cachedRefs = { - resource: document.uri, - version, - position, - references, - triggerRef - }; - return this.cachedRefs; - } -} - - -export function registerRenameSupport( - selector: vscode.DocumentSelector, - workspace: IMdWorkspace, - referencesProvider: MdReferencesProvider, - slugifier: Slugifier, -): vscode.Disposable { - return vscode.languages.registerRenameProvider(selector, new MdVsCodeRenameProvider(workspace, referencesProvider, slugifier)); -} diff --git a/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts b/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts deleted file mode 100644 index 29f0e922559..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts +++ /dev/null @@ -1,258 +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 Token = require('markdown-it/lib/token'); -import * as vscode from 'vscode'; -import { IMdParser } from '../markdownEngine'; -import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; - -interface MarkdownItTokenWithMap extends Token { - map: [number, number]; -} - -export class MdSmartSelect implements vscode.SelectionRangeProvider { - - constructor( - private readonly parser: IMdParser, - private readonly tocProvider: MdTableOfContentsProvider, - ) { } - - public async provideSelectionRanges(document: ITextDocument, positions: vscode.Position[], _token: vscode.CancellationToken): Promise { - const promises = await Promise.all(positions.map((position) => { - return this.provideSelectionRange(document, position, _token); - })); - return promises.filter(item => item !== undefined) as vscode.SelectionRange[]; - } - - private async provideSelectionRange(document: ITextDocument, position: vscode.Position, _token: vscode.CancellationToken): Promise { - const headerRange = await this.getHeaderSelectionRange(document, position); - const blockRange = await this.getBlockSelectionRange(document, position, headerRange); - const inlineRange = await this.getInlineSelectionRange(document, position, blockRange); - return inlineRange || blockRange || headerRange; - } - private async getInlineSelectionRange(document: ITextDocument, position: vscode.Position, blockRange?: vscode.SelectionRange): Promise { - return createInlineRange(document, position, blockRange); - } - - private async getBlockSelectionRange(document: ITextDocument, position: vscode.Position, headerRange?: vscode.SelectionRange): Promise { - const tokens = await this.parser.tokenize(document); - const blockTokens = getBlockTokensForPosition(tokens, position, headerRange); - - if (blockTokens.length === 0) { - return undefined; - } - - let currentRange: vscode.SelectionRange | undefined = headerRange ? headerRange : createBlockRange(blockTokens.shift()!, document, position.line); - - for (let i = 0; i < blockTokens.length; i++) { - currentRange = createBlockRange(blockTokens[i], document, position.line, currentRange); - } - return currentRange; - } - - private async getHeaderSelectionRange(document: ITextDocument, position: vscode.Position): Promise { - const toc = await this.tocProvider.getForDocument(document); - - const headerInfo = getHeadersForPosition(toc.entries, position); - - const headers = headerInfo.headers; - - let currentRange: vscode.SelectionRange | undefined; - - for (let i = 0; i < headers.length; i++) { - currentRange = createHeaderRange(headers[i], i === headers.length - 1, headerInfo.headerOnThisLine, currentRange, getFirstChildHeader(document, headers[i], toc.entries)); - } - return currentRange; - } -} - -function getHeadersForPosition(toc: readonly TocEntry[], position: vscode.Position): { headers: TocEntry[]; headerOnThisLine: boolean } { - const enclosingHeaders = toc.filter(header => header.sectionLocation.range.start.line <= position.line && header.sectionLocation.range.end.line >= position.line); - const sortedHeaders = enclosingHeaders.sort((header1, header2) => (header1.line - position.line) - (header2.line - position.line)); - const onThisLine = toc.find(header => header.line === position.line) !== undefined; - return { - headers: sortedHeaders, - headerOnThisLine: onThisLine - }; -} - -function createHeaderRange(header: TocEntry, isClosestHeaderToPosition: boolean, onHeaderLine: boolean, parent?: vscode.SelectionRange, startOfChildRange?: vscode.Position): vscode.SelectionRange | undefined { - const range = header.sectionLocation.range; - const contentRange = new vscode.Range(range.start.translate(1), range.end); - if (onHeaderLine && isClosestHeaderToPosition && startOfChildRange) { - // selection was made on this header line, so select header and its content until the start of its first child - // then all of its content - return new vscode.SelectionRange(range.with(undefined, startOfChildRange), new vscode.SelectionRange(range, parent)); - } else if (onHeaderLine && isClosestHeaderToPosition) { - // selection was made on this header line and no children so expand to all of its content - return new vscode.SelectionRange(range, parent); - } else if (isClosestHeaderToPosition && startOfChildRange) { - // selection was made within content and has child so select content - // of this header then all content then header - return new vscode.SelectionRange(contentRange.with(undefined, startOfChildRange), new vscode.SelectionRange(contentRange, (new vscode.SelectionRange(range, parent)))); - } else { - // not on this header line so select content then header - return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent)); - } -} - -function getBlockTokensForPosition(tokens: Token[], position: vscode.Position, parent?: vscode.SelectionRange): MarkdownItTokenWithMap[] { - const enclosingTokens = tokens.filter((token): token is MarkdownItTokenWithMap => !!token.map && (token.map[0] <= position.line && token.map[1] > position.line) && (!parent || (token.map[0] >= parent.range.start.line && token.map[1] <= parent.range.end.line + 1)) && isBlockElement(token)); - if (enclosingTokens.length === 0) { - return []; - } - const sortedTokens = enclosingTokens.sort((token1, token2) => (token2.map[1] - token2.map[0]) - (token1.map[1] - token1.map[0])); - return sortedTokens; -} - -function createBlockRange(block: MarkdownItTokenWithMap, document: ITextDocument, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - if (block.type === 'fence') { - return createFencedRange(block, cursorLine, document, parent); - } else { - let startLine = document.lineAt(block.map[0]).isEmptyOrWhitespace ? block.map[0] + 1 : block.map[0]; - let endLine = startLine === block.map[1] ? block.map[1] : block.map[1] - 1; - if (block.type === 'paragraph_open' && block.map[1] - block.map[0] === 2) { - startLine = endLine = cursorLine; - } else if (isList(block) && document.lineAt(endLine).isEmptyOrWhitespace) { - endLine = endLine - 1; - } - const range = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text?.length ?? 0); - if (parent?.range.contains(range) && !parent.range.isEqual(range)) { - return new vscode.SelectionRange(range, parent); - } else if (parent?.range.isEqual(range)) { - return parent; - } else { - return new vscode.SelectionRange(range); - } - } -} - -function createInlineRange(document: ITextDocument, cursorPosition: vscode.Position, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const lineText = document.lineAt(cursorPosition.line).text; - const boldSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, parent); - const italicSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, parent); - let comboSelection: vscode.SelectionRange | undefined; - if (boldSelection && italicSelection && !boldSelection.range.isEqual(italicSelection.range)) { - if (boldSelection.range.contains(italicSelection.range)) { - comboSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, boldSelection); - } else if (italicSelection.range.contains(boldSelection.range)) { - comboSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, italicSelection); - } - } - const linkSelection = createLinkRange(lineText, cursorPosition.character, cursorPosition.line, comboSelection || boldSelection || italicSelection || parent); - const inlineCodeBlockSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, false, linkSelection || parent); - return inlineCodeBlockSelection || linkSelection || comboSelection || boldSelection || italicSelection; -} - -function createFencedRange(token: MarkdownItTokenWithMap, cursorLine: number, document: ITextDocument, parent?: vscode.SelectionRange): vscode.SelectionRange { - const startLine = token.map[0]; - const endLine = token.map[1] - 1; - const onFenceLine = cursorLine === startLine || cursorLine === endLine; - const fenceRange = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text.length); - const contentRange = endLine - startLine > 2 && !onFenceLine ? new vscode.Range(startLine + 1, 0, endLine - 1, document.lineAt(endLine - 1).text.length) : undefined; - if (contentRange) { - return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(fenceRange, parent)); - } else { - if (parent?.range.isEqual(fenceRange)) { - return parent; - } else { - return new vscode.SelectionRange(fenceRange, parent); - } - } -} - -function createBoldRange(lineText: string, cursorChar: number, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const regex = /\*\*([^*]+\*?[^*]+\*?[^*]+)\*\*/gim; - const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar); - if (matches.length) { - // should only be one match, so select first and index 0 contains the entire match - const bold = matches[0][0]; - const startIndex = lineText.indexOf(bold); - const cursorOnStars = cursorChar === startIndex || cursorChar === startIndex + 1 || cursorChar === startIndex + bold.length || cursorChar === startIndex + bold.length - 1; - const contentAndStars = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + bold.length), parent); - const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 2, cursorLine, startIndex + bold.length - 2), contentAndStars); - return cursorOnStars ? contentAndStars : content; - } - return undefined; -} - -function createOtherInlineRange(lineText: string, cursorChar: number, cursorLine: number, isItalic: boolean, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const italicRegexes = [/(?:[^*]+)(\*([^*]+)(?:\*\*[^*]*\*\*)*([^*]+)\*)(?:[^*]+)/g, /^(?:[^*]*)(\*([^*]+)(?:\*\*[^*]*\*\*)*([^*]+)\*)(?:[^*]*)$/g]; - let matches = []; - if (isItalic) { - matches = [...lineText.matchAll(italicRegexes[0])].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar); - if (!matches.length) { - matches = [...lineText.matchAll(italicRegexes[1])].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar); - } - } else { - matches = [...lineText.matchAll(/\`[^\`]*\`/g)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar); - } - if (matches.length) { - // should only be one match, so select first and select group 1 for italics because that contains just the italic section - // doesn't include the leading and trailing characters which are guaranteed to not be * so as not to be confused with bold - const match = isItalic ? matches[0][1] : matches[0][0]; - const startIndex = lineText.indexOf(match); - const cursorOnType = cursorChar === startIndex || cursorChar === startIndex + match.length; - const contentAndType = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + match.length), parent); - const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 1, cursorLine, startIndex + match.length - 1), contentAndType); - return cursorOnType ? contentAndType : content; - } - return undefined; -} - -function createLinkRange(lineText: string, cursorChar: number, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const regex = /(\[[^\(\)]*\])(\([^\[\]]*\))/g; - const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length > cursorChar); - - if (matches.length) { - // should only be one match, so select first and index 0 contains the entire match, so match = [text](url) - const link = matches[0][0]; - const linkRange = new vscode.SelectionRange(new vscode.Range(cursorLine, lineText.indexOf(link), cursorLine, lineText.indexOf(link) + link.length), parent); - - const linkText = matches[0][1]; - const url = matches[0][2]; - - // determine if cursor is within [text] or (url) in order to know which should be selected - const nearestType = cursorChar >= lineText.indexOf(linkText) && cursorChar < lineText.indexOf(linkText) + linkText.length ? linkText : url; - - const indexOfType = lineText.indexOf(nearestType); - // determine if cursor is on a bracket or paren and if so, return the [content] or (content), skipping over the content range - const cursorOnType = cursorChar === indexOfType || cursorChar === indexOfType + nearestType.length; - - const contentAndNearestType = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType, cursorLine, indexOfType + nearestType.length), linkRange); - const content = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType + 1, cursorLine, indexOfType + nearestType.length - 1), contentAndNearestType); - return cursorOnType ? contentAndNearestType : content; - } - return undefined; -} - -function isList(token: Token): boolean { - return token.type ? ['ordered_list_open', 'list_item_open', 'bullet_list_open'].includes(token.type) : false; -} - -function isBlockElement(token: Token): boolean { - return !['list_item_close', 'paragraph_close', 'bullet_list_close', 'inline', 'heading_close', 'heading_open'].includes(token.type); -} - -function getFirstChildHeader(document: ITextDocument, header?: TocEntry, toc?: readonly TocEntry[]): vscode.Position | undefined { - let childRange: vscode.Position | undefined; - if (header && toc) { - const children = toc.filter(t => header.sectionLocation.range.contains(t.sectionLocation.range) && t.sectionLocation.range.start.line > header.sectionLocation.range.start.line).sort((t1, t2) => t1.line - t2.line); - if (children.length > 0) { - childRange = children[0].sectionLocation.range.start; - const lineText = document.lineAt(childRange.line - 1).text; - return childRange ? childRange.translate(-1, lineText.length) : undefined; - } - } - return undefined; -} - -export function registerSmartSelectSupport( - selector: vscode.DocumentSelector, - parser: IMdParser, - tocProvider: MdTableOfContentsProvider, -): vscode.Disposable { - return vscode.languages.registerSelectionRangeProvider(selector, new MdSmartSelect(parser, tocProvider)); -} diff --git a/extensions/markdown-language-features/src/languageFeatures/workspaceSymbols.ts b/extensions/markdown-language-features/src/languageFeatures/workspaceSymbols.ts deleted file mode 100644 index 1bbef509791..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/workspaceSymbols.ts +++ /dev/null @@ -1,36 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { Disposable } from '../util/dispose'; -import { MdWorkspaceInfoCache } from '../util/workspaceCache'; -import { IMdWorkspace } from '../workspace'; -import { MdDocumentSymbolProvider } from './documentSymbols'; - -export class MdWorkspaceSymbolProvider extends Disposable implements vscode.WorkspaceSymbolProvider { - - private readonly _cache: MdWorkspaceInfoCache; - - public constructor( - symbolProvider: MdDocumentSymbolProvider, - workspace: IMdWorkspace, - ) { - super(); - - this._cache = this._register(new MdWorkspaceInfoCache(workspace, doc => symbolProvider.provideDocumentSymbolInformation(doc))); - } - - public async provideWorkspaceSymbols(query: string): Promise { - const allSymbols = (await this._cache.values()).flat(); - return allSymbols.filter(symbolInformation => symbolInformation.name.toLowerCase().indexOf(query.toLowerCase()) !== -1); - } -} - -export function registerWorkspaceSymbolSupport( - workspace: IMdWorkspace, - symbolProvider: MdDocumentSymbolProvider, -): vscode.Disposable { - return vscode.languages.registerWorkspaceSymbolProvider(new MdWorkspaceSymbolProvider(symbolProvider, workspace)); -} diff --git a/extensions/markdown-language-features/src/logging.ts b/extensions/markdown-language-features/src/logging.ts index 48a2f3a7709..5947af62409 100644 --- a/extensions/markdown-language-features/src/logging.ts +++ b/extensions/markdown-language-features/src/logging.ts @@ -70,7 +70,7 @@ export class VsCodeOutputLogger extends Disposable implements ILogger { } private readTrace(): Trace { - return Trace.fromString(vscode.workspace.getConfiguration().get('markdown.trace', 'off')); + return Trace.fromString(vscode.workspace.getConfiguration().get('markdown.trace.extension', 'off')); } private static data2String(data: any): string { diff --git a/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts index b8d060e2099..de06df4ffeb 100644 --- a/extensions/markdown-language-features/src/markdownEngine.ts +++ b/extensions/markdown-language-features/src/markdownEngine.ts @@ -10,12 +10,8 @@ import { ILogger } from './logging'; import { MarkdownContributionProvider } from './markdownExtensions'; import { Slugifier } from './slugify'; import { ITextDocument } from './types/textDocument'; -import { Disposable } from './util/dispose'; -import { stringHash } from './util/hash'; import { WebviewResourceProvider } from './util/resources'; import { isOfScheme, Schemes } from './util/schemes'; -import { MdDocumentInfoCache } from './util/workspaceCache'; -import { IMdWorkspace } from './workspace'; const UNICODE_NEWLINE_REGEX = /\u2028|\u2029/g; @@ -86,11 +82,11 @@ class TokenCache { export interface RenderOutput { html: string; - containingImages: { src: string }[]; + containingImages: Set; } interface RenderEnv { - containingImages: { src: string }[]; + containingImages: Set; currentDocument: vscode.Uri | undefined; resourceProvider: WebviewResourceProvider | undefined; } @@ -209,7 +205,7 @@ export class MarkdownItEngine implements IMdParser { : this.tokenizeDocument(input, config, engine); const env: RenderEnv = { - containingImages: [], + containingImages: new Set(), currentDocument: typeof input === 'string' ? undefined : input.uri, resourceProvider, }; @@ -248,13 +244,9 @@ export class MarkdownItEngine implements IMdParser { const original = md.renderer.rules.image; md.renderer.rules.image = (tokens: Token[], idx: number, options, env: RenderEnv, self) => { const token = tokens[idx]; - token.attrJoin('class', 'loading'); - const src = token.attrGet('src'); if (src) { - env.containingImages?.push({ src }); - const imgHash = stringHash(src); - token.attrSet('id', `image-hash-${imgHash}`); + env.containingImages?.add(src); if (!token.attrGet('data-src')) { token.attrSet('src', this.toResourceUri(src, env.currentDocument, env.resourceProvider)); @@ -439,27 +431,3 @@ function normalizeHighlightLang(lang: string | undefined) { return lang; } } - -export class MdParsingProvider extends Disposable implements IMdParser { - - private readonly _cache: MdDocumentInfoCache; - - public readonly slugifier: Slugifier; - - constructor( - engine: MarkdownItEngine, - workspace: IMdWorkspace, - ) { - super(); - - this.slugifier = engine.slugifier; - - this._cache = this._register(new MdDocumentInfoCache(workspace, doc => { - return engine.tokenize(doc); - })); - } - - public tokenize(document: ITextDocument): Promise { - return this._cache.getForDocument(document); - } -} diff --git a/extensions/markdown-language-features/src/preview/documentRenderer.ts b/extensions/markdown-language-features/src/preview/documentRenderer.ts index 28e25cef6ef..8acbb9db2a9 100644 --- a/extensions/markdown-language-features/src/preview/documentRenderer.ts +++ b/extensions/markdown-language-features/src/preview/documentRenderer.ts @@ -38,7 +38,7 @@ const previewStrings = { export interface MarkdownContentProviderOutput { html: string; - containingImages: { src: string }[]; + containingImages: Set; } @@ -88,7 +88,7 @@ export class MdDocumentRenderer { const body = await this.renderBody(markdownDocument, resourceProvider); if (token.isCancellationRequested) { - return { html: '', containingImages: [] }; + return { html: '', containingImages: new Set() }; } const html = ` diff --git a/extensions/markdown-language-features/src/preview/preview.ts b/extensions/markdown-language-features/src/preview/preview.ts index 6e792d36edc..b4f4cb7f3b2 100644 --- a/extensions/markdown-language-features/src/preview/preview.ts +++ b/extensions/markdown-language-features/src/preview/preview.ts @@ -8,13 +8,11 @@ import * as nls from 'vscode-nls'; import * as uri from 'vscode-uri'; import { ILogger } from '../logging'; import { MarkdownContributionProvider } from '../markdownExtensions'; -import { MdTableOfContentsProvider } from '../tableOfContents'; import { Disposable } from '../util/dispose'; import { isMarkdownFile } from '../util/file'; -import { openDocumentLink, resolveDocumentLink, resolveUriToMarkdownFile } from '../util/openDocumentLink'; +import { MdLinkOpener } from '../util/openDocumentLink'; import { WebviewResourceProvider } from '../util/resources'; import { urlToUri } from '../util/url'; -import { IMdWorkspace } from '../workspace'; import { MdDocumentRenderer } from './documentRenderer'; import { MarkdownPreviewConfigurationManager } from './previewConfig'; import { scrollEditorToLine, StartingScrollFragment, StartingScrollLine, StartingScrollLocation } from './scrolling'; @@ -119,10 +117,9 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { private readonly delegate: MarkdownPreviewDelegate, private readonly _contentProvider: MdDocumentRenderer, private readonly _previewConfigurations: MarkdownPreviewConfigurationManager, - private readonly _workspace: IMdWorkspace, private readonly _logger: ILogger, private readonly _contributionProvider: MarkdownContributionProvider, - private readonly _tocProvider: MdTableOfContentsProvider, + private readonly _opener: MdLinkOpener, ) { super(); @@ -396,9 +393,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { } } - private updateImageWatchers(containingImages: { src: string }[]) { - const srcs = new Set(containingImages.map(img => img.src)); - + private updateImageWatchers(srcs: Set) { // Delete stale file watchers. for (const [src, watcher] of this._fileWatchersBySrc) { if (!srcs.has(src)) { @@ -446,19 +441,23 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { } private async onDidClickPreviewLink(href: string) { - const targetResource = resolveDocumentLink(href, this.resource); - const config = vscode.workspace.getConfiguration('markdown', this.resource); const openLinks = config.get('preview.openMarkdownLinks', 'inPreview'); if (openLinks === 'inPreview') { - const linkedDoc = await resolveUriToMarkdownFile(this._workspace, targetResource); - if (linkedDoc) { - this.delegate.openPreviewLinkToMarkdownFile(linkedDoc.uri, targetResource.fragment); - return; + const resolved = await this._opener.resolveDocumentLink(href, this.resource); + if (resolved.kind === 'file') { + try { + const doc = await vscode.workspace.openTextDocument(vscode.Uri.from(resolved.uri)); + if (isMarkdownFile(doc)) { + return this.delegate.openPreviewLinkToMarkdownFile(doc.uri, resolved.fragment ?? ''); + } + } catch { + // Noop + } } } - return openDocumentLink(this._tocProvider, targetResource, this.resource); + return this._opener.openDocumentLink(href, this.resource); } //#region WebviewResourceProvider @@ -504,13 +503,12 @@ export class StaticMarkdownPreview extends Disposable implements IManagedMarkdow contentProvider: MdDocumentRenderer, previewConfigurations: MarkdownPreviewConfigurationManager, topmostLineMonitor: TopmostLineMonitor, - workspace: IMdWorkspace, logger: ILogger, contributionProvider: MarkdownContributionProvider, - tocProvider: MdTableOfContentsProvider, + opener: MdLinkOpener, scrollLine?: number, ): StaticMarkdownPreview { - return new StaticMarkdownPreview(webview, resource, contentProvider, previewConfigurations, topmostLineMonitor, workspace, logger, contributionProvider, tocProvider, scrollLine); + return new StaticMarkdownPreview(webview, resource, contentProvider, previewConfigurations, topmostLineMonitor, logger, contributionProvider, opener, scrollLine); } private readonly preview: MarkdownPreview; @@ -521,10 +519,9 @@ export class StaticMarkdownPreview extends Disposable implements IManagedMarkdow contentProvider: MdDocumentRenderer, private readonly _previewConfigurations: MarkdownPreviewConfigurationManager, topmostLineMonitor: TopmostLineMonitor, - workspace: IMdWorkspace, logger: ILogger, contributionProvider: MarkdownContributionProvider, - tocProvider: MdTableOfContentsProvider, + opener: MdLinkOpener, scrollLine?: number, ) { super(); @@ -536,7 +533,7 @@ export class StaticMarkdownPreview extends Disposable implements IManagedMarkdow fragment }), StaticMarkdownPreview.customEditorViewType, this._webviewPanel.viewColumn); } - }, contentProvider, _previewConfigurations, workspace, logger, contributionProvider, tocProvider)); + }, contentProvider, _previewConfigurations, logger, contributionProvider, opener)); this._register(this._webviewPanel.onDidDispose(() => { this.dispose(); @@ -617,16 +614,15 @@ export class DynamicMarkdownPreview extends Disposable implements IManagedMarkdo webview: vscode.WebviewPanel, contentProvider: MdDocumentRenderer, previewConfigurations: MarkdownPreviewConfigurationManager, - workspace: IMdWorkspace, logger: ILogger, topmostLineMonitor: TopmostLineMonitor, contributionProvider: MarkdownContributionProvider, - tocProvider: MdTableOfContentsProvider, + opener: MdLinkOpener, ): DynamicMarkdownPreview { webview.iconPath = contentProvider.iconPath; return new DynamicMarkdownPreview(webview, input, - contentProvider, previewConfigurations, workspace, logger, topmostLineMonitor, contributionProvider, tocProvider); + contentProvider, previewConfigurations, logger, topmostLineMonitor, contributionProvider, opener); } public static create( @@ -634,11 +630,10 @@ export class DynamicMarkdownPreview extends Disposable implements IManagedMarkdo previewColumn: vscode.ViewColumn, contentProvider: MdDocumentRenderer, previewConfigurations: MarkdownPreviewConfigurationManager, - workspace: IMdWorkspace, logger: ILogger, topmostLineMonitor: TopmostLineMonitor, contributionProvider: MarkdownContributionProvider, - tocProvider: MdTableOfContentsProvider, + opener: MdLinkOpener, ): DynamicMarkdownPreview { const webview = vscode.window.createWebviewPanel( DynamicMarkdownPreview.viewType, @@ -648,7 +643,7 @@ export class DynamicMarkdownPreview extends Disposable implements IManagedMarkdo webview.iconPath = contentProvider.iconPath; return new DynamicMarkdownPreview(webview, input, - contentProvider, previewConfigurations, workspace, logger, topmostLineMonitor, contributionProvider, tocProvider); + contentProvider, previewConfigurations, logger, topmostLineMonitor, contributionProvider, opener); } private constructor( @@ -656,11 +651,10 @@ export class DynamicMarkdownPreview extends Disposable implements IManagedMarkdo input: DynamicPreviewInput, private readonly _contentProvider: MdDocumentRenderer, private readonly _previewConfigurations: MarkdownPreviewConfigurationManager, - private readonly _workspace: IMdWorkspace, private readonly _logger: ILogger, private readonly _topmostLineMonitor: TopmostLineMonitor, private readonly _contributionProvider: MarkdownContributionProvider, - private readonly _tocProvider: MdTableOfContentsProvider, + private readonly _opener: MdLinkOpener, ) { super(); @@ -814,9 +808,8 @@ export class DynamicMarkdownPreview extends Disposable implements IManagedMarkdo }, this._contentProvider, this._previewConfigurations, - this._workspace, this._logger, this._contributionProvider, - this._tocProvider); + this._opener); } } diff --git a/extensions/markdown-language-features/src/preview/previewManager.ts b/extensions/markdown-language-features/src/preview/previewManager.ts index 134989ce181..50196ac882e 100644 --- a/extensions/markdown-language-features/src/preview/previewManager.ts +++ b/extensions/markdown-language-features/src/preview/previewManager.ts @@ -4,18 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; import { ILogger } from '../logging'; import { MarkdownContributionProvider } from '../markdownExtensions'; -import { MdTableOfContentsProvider } from '../tableOfContents'; import { Disposable, disposeAll } from '../util/dispose'; import { isMarkdownFile } from '../util/file'; -import { IMdWorkspace } from '../workspace'; +import { MdLinkOpener } from '../util/openDocumentLink'; import { MdDocumentRenderer } from './documentRenderer'; import { DynamicMarkdownPreview, IManagedMarkdownPreview, StaticMarkdownPreview } from './preview'; import { MarkdownPreviewConfigurationManager } from './previewConfig'; import { scrollEditorToLine, StartingScrollFragment } from './scrolling'; import { TopmostLineMonitor } from './topmostLineMonitor'; +const localize = nls.loadMessageBundle(); + + export interface DynamicPreviewSettings { readonly resourceColumn: vscode.ViewColumn; readonly previewColumn: vscode.ViewColumn; @@ -58,8 +61,6 @@ class PreviewStore extends Disposable { export class MarkdownPreviewManager extends Disposable implements vscode.WebviewPanelSerializer, vscode.CustomTextEditorProvider { - private static readonly markdownPreviewActiveContextKey = 'markdownPreviewFocus'; - private readonly _topmostLineMonitor = new TopmostLineMonitor(); private readonly _previewConfigurations = new MarkdownPreviewConfigurationManager(); @@ -70,10 +71,9 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview public constructor( private readonly _contentProvider: MdDocumentRenderer, - private readonly _workspace: IMdWorkspace, private readonly _logger: ILogger, private readonly _contributions: MarkdownContributionProvider, - private readonly _tocProvider: MdTableOfContentsProvider, + private readonly _opener: MdLinkOpener, ) { super(); @@ -155,23 +155,58 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview webview: vscode.WebviewPanel, state: any ): Promise { - const resource = vscode.Uri.parse(state.resource); - const locked = state.locked; - const line = state.line; - const resourceColumn = state.resourceColumn; + try { + const resource = vscode.Uri.parse(state.resource); + const locked = state.locked; + const line = state.line; + const resourceColumn = state.resourceColumn; - const preview = await DynamicMarkdownPreview.revive( - { resource, locked, line, resourceColumn }, - webview, - this._contentProvider, - this._previewConfigurations, - this._workspace, - this._logger, - this._topmostLineMonitor, - this._contributions, - this._tocProvider); + const preview = DynamicMarkdownPreview.revive( + { resource, locked, line, resourceColumn }, + webview, + this._contentProvider, + this._previewConfigurations, + this._logger, + this._topmostLineMonitor, + this._contributions, + this._opener); - this.registerDynamicPreview(preview); + this.registerDynamicPreview(preview); + } catch (e) { + console.error(e); + + webview.webview.html = /* html */` + + + + + + + + Markdown Preview + + + + + + +

${localize('preview.restoreError', "An unexpected error occurred while restoring the Markdown preview.")}

+ + `; + } } public async resolveCustomTextEditor( @@ -185,10 +220,9 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview this._contentProvider, this._previewConfigurations, this._topmostLineMonitor, - this._workspace, this._logger, this._contributions, - this._tocProvider, + this._opener, lineNumber ); this.registerStaticPreview(preview); @@ -210,13 +244,11 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview previewSettings.previewColumn, this._contentProvider, this._previewConfigurations, - this._workspace, this._logger, this._topmostLineMonitor, this._contributions, - this._tocProvider); + this._opener); - this.setPreviewActiveContext(true); this._activePreview = preview; return this.registerDynamicPreview(preview); } @@ -250,19 +282,14 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview private trackActive(preview: IManagedMarkdownPreview): void { preview.onDidChangeViewState(({ webviewPanel }) => { - this.setPreviewActiveContext(webviewPanel.active); this._activePreview = webviewPanel.active ? preview : undefined; }); preview.onDispose(() => { if (this._activePreview === preview) { - this.setPreviewActiveContext(false); this._activePreview = undefined; } }); } - private setPreviewActiveContext(value: boolean) { - vscode.commands.executeCommand('setContext', MarkdownPreviewManager.markdownPreviewActiveContextKey, value); - } } diff --git a/extensions/markdown-language-features/src/protocol.ts b/extensions/markdown-language-features/src/protocol.ts new file mode 100644 index 00000000000..92ec2c0e80a --- /dev/null +++ b/extensions/markdown-language-features/src/protocol.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 type Token = require('markdown-it/lib/token'); +import * as vscode from 'vscode'; +import { RequestType } from 'vscode-languageclient'; +import type * as lsp from 'vscode-languageserver-types'; +import type * as md from 'vscode-markdown-languageservice'; + + +export type ResolvedDocumentLinkTarget = + | { readonly kind: 'file'; readonly uri: vscode.Uri; position?: lsp.Position; fragment?: string } + | { readonly kind: 'folder'; readonly uri: vscode.Uri } + | { readonly kind: 'external'; readonly uri: vscode.Uri }; + +//#region From server +export const parse = new RequestType<{ uri: string }, Token[], any>('markdown/parse'); + +export const fs_readFile = new RequestType<{ uri: string }, number[], any>('markdown/fs/readFile'); +export const fs_readDirectory = new RequestType<{ uri: string }, [string, { isDirectory: boolean }][], any>('markdown/fs/readDirectory'); +export const fs_stat = new RequestType<{ uri: string }, { isDirectory: boolean } | undefined, any>('markdown/fs/stat'); + +export const fs_watcher_create = new RequestType<{ id: number; uri: string; options: md.FileWatcherOptions; watchParentDirs: boolean }, void, any>('markdown/fs/watcher/create'); +export const fs_watcher_delete = new RequestType<{ id: number }, void, any>('markdown/fs/watcher/delete'); + +export const findMarkdownFilesInWorkspace = new RequestType<{}, string[], any>('markdown/findMarkdownFilesInWorkspace'); +//#endregion + +//#region To server +export const getReferencesToFileInWorkspace = new RequestType<{ uri: string }, lsp.Location[], any>('markdown/getReferencesToFileInWorkspace'); +export const getEditForFileRenames = new RequestType, lsp.WorkspaceEdit, any>('markdown/getEditForFileRenames'); + +export const fs_watcher_onChange = new RequestType<{ id: number; uri: string; kind: 'create' | 'change' | 'delete' }, void, any>('markdown/fs/watcher/onChange'); + +export const resolveLinkTarget = new RequestType<{ linkText: string; uri: string }, ResolvedDocumentLinkTarget, any>('markdown/resolveLinkTarget'); +//#endregion diff --git a/extensions/markdown-language-features/src/tableOfContents.ts b/extensions/markdown-language-features/src/tableOfContents.ts deleted file mode 100644 index b1e3e25c8d3..00000000000 --- a/extensions/markdown-language-features/src/tableOfContents.ts +++ /dev/null @@ -1,213 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { ILogger } from './logging'; -import { IMdParser } from './markdownEngine'; -import { githubSlugifier, Slug, Slugifier } from './slugify'; -import { ITextDocument } from './types/textDocument'; -import { Disposable } from './util/dispose'; -import { isMarkdownFile } from './util/file'; -import { Schemes } from './util/schemes'; -import { MdDocumentInfoCache } from './util/workspaceCache'; -import { IMdWorkspace } from './workspace'; - -export interface TocEntry { - readonly slug: Slug; - readonly text: string; - readonly level: number; - readonly line: number; - - /** - * The entire range of the header section. - * - * For the doc: - * - * ```md - * # Head # - * text - * # Next head # - * ``` - * - * This is the range from `# Head #` to `# Next head #` - */ - readonly sectionLocation: vscode.Location; - - /** - * The range of the header declaration. - * - * For the doc: - * - * ```md - * # Head # - * text - * ``` - * - * This is the range of `# Head #` - */ - readonly headerLocation: vscode.Location; - - /** - * The range of the header text. - * - * For the doc: - * - * ```md - * # Head # - * text - * ``` - * - * This is the range of `Head` - */ - readonly headerTextLocation: vscode.Location; -} - -export class TableOfContents { - - public static async create(parser: IMdParser, document: ITextDocument,): Promise { - const entries = await this.buildToc(parser, document); - return new TableOfContents(entries, parser.slugifier); - } - - public static async createForDocumentOrNotebook(parser: IMdParser, document: ITextDocument): Promise { - if (document.uri.scheme === Schemes.notebookCell) { - const notebook = vscode.workspace.notebookDocuments - .find(notebook => notebook.getCells().some(cell => cell.document === document)); - - if (notebook) { - return TableOfContents.createForNotebook(parser, notebook); - } - } - - return this.create(parser, document); - } - - public static async createForNotebook(parser: IMdParser, notebook: vscode.NotebookDocument): Promise { - const entries: TocEntry[] = []; - - for (const cell of notebook.getCells()) { - if (cell.kind === vscode.NotebookCellKind.Markup && isMarkdownFile(cell.document)) { - entries.push(...(await this.buildToc(parser, cell.document))); - } - } - - return new TableOfContents(entries, parser.slugifier); - } - - private static async buildToc(parser: IMdParser, document: ITextDocument): Promise { - const toc: TocEntry[] = []; - const tokens = await parser.tokenize(document); - - const existingSlugEntries = new Map(); - - for (const heading of tokens.filter(token => token.type === 'heading_open')) { - if (!heading.map) { - continue; - } - - const lineNumber = heading.map[0]; - const line = document.lineAt(lineNumber); - - let slug = parser.slugifier.fromHeading(line.text); - const existingSlugEntry = existingSlugEntries.get(slug.value); - if (existingSlugEntry) { - ++existingSlugEntry.count; - slug = parser.slugifier.fromHeading(slug.value + '-' + existingSlugEntry.count); - } else { - existingSlugEntries.set(slug.value, { count: 0 }); - } - - const headerLocation = new vscode.Location(document.uri, - new vscode.Range(lineNumber, 0, lineNumber, line.text.length)); - - const headerTextLocation = new vscode.Location(document.uri, - new vscode.Range(lineNumber, line.text.match(/^#+\s*/)?.[0].length ?? 0, lineNumber, line.text.length - (line.text.match(/\s*#*$/)?.[0].length ?? 0))); - - toc.push({ - slug, - text: TableOfContents.getHeaderText(line.text), - level: TableOfContents.getHeaderLevel(heading.markup), - line: lineNumber, - sectionLocation: headerLocation, // Populated in next steps - headerLocation, - headerTextLocation - }); - } - - // Get full range of section - return toc.map((entry, startIndex): TocEntry => { - let end: number | undefined = undefined; - for (let i = startIndex + 1; i < toc.length; ++i) { - if (toc[i].level <= entry.level) { - end = toc[i].line - 1; - break; - } - } - const endLine = end ?? document.lineCount - 1; - return { - ...entry, - sectionLocation: new vscode.Location(document.uri, - new vscode.Range( - entry.sectionLocation.range.start, - new vscode.Position(endLine, document.lineAt(endLine).text.length))) - }; - }); - } - - private static getHeaderLevel(markup: string): number { - if (markup === '=') { - return 1; - } else if (markup === '-') { - return 2; - } else { // '#', '##', ... - return markup.length; - } - } - - private static getHeaderText(header: string): string { - return header.replace(/^\s*#+\s*(.*?)(\s+#+)?$/, (_, word) => word.trim()); - } - - public static readonly empty = new TableOfContents([], githubSlugifier); - - private constructor( - public readonly entries: readonly TocEntry[], - private readonly slugifier: Slugifier, - ) { } - - public lookup(fragment: string): TocEntry | undefined { - const slug = this.slugifier.fromHeading(fragment); - return this.entries.find(entry => entry.slug.equals(slug)); - } -} - -export class MdTableOfContentsProvider extends Disposable { - - private readonly _cache: MdDocumentInfoCache; - - constructor( - private readonly parser: IMdParser, - workspace: IMdWorkspace, - private readonly logger: ILogger, - ) { - super(); - this._cache = this._register(new MdDocumentInfoCache(workspace, doc => { - this.logger.verbose('TableOfContentsProvider', `create - ${doc.uri}`); - return TableOfContents.create(parser, doc); - })); - } - - public async get(resource: vscode.Uri): Promise { - return await this._cache.get(resource) ?? TableOfContents.empty; - } - - public getForDocument(doc: ITextDocument): Promise { - return this._cache.getForDocument(doc); - } - - public createForNotebook(notebook: vscode.NotebookDocument): Promise { - return TableOfContents.createForNotebook(this.parser, notebook); - } -} diff --git a/extensions/markdown-language-features/src/test/definitionProvider.test.ts b/extensions/markdown-language-features/src/test/definitionProvider.test.ts deleted file mode 100644 index 66c8919b5ba..00000000000 --- a/extensions/markdown-language-features/src/test/definitionProvider.test.ts +++ /dev/null @@ -1,144 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { MdVsCodeDefinitionProvider } from '../languageFeatures/definitions'; -import { MdReferencesProvider } from '../languageFeatures/references'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { noopToken } from '../util/cancellation'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { IMdWorkspace } from '../workspace'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { joinLines, withStore, workspacePath } from './util'; - - -function getDefinition(store: DisposableStore, doc: InMemoryDocument, pos: vscode.Position, workspace: IMdWorkspace) { - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const referencesProvider = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); - const provider = new MdVsCodeDefinitionProvider(referencesProvider); - return provider.provideDefinition(doc, pos, noopToken); -} - -function assertDefinitionsEqual(actualDef: vscode.Definition, ...expectedDefs: { uri: vscode.Uri; line: number; startCharacter?: number; endCharacter?: number }[]) { - const actualDefsArr = Array.isArray(actualDef) ? actualDef : [actualDef]; - - assert.strictEqual(actualDefsArr.length, expectedDefs.length, `Definition counts should match`); - - for (let i = 0; i < actualDefsArr.length; ++i) { - const actual = actualDefsArr[i]; - const expected = expectedDefs[i]; - assert.strictEqual(actual.uri.toString(), expected.uri.toString(), `Definition '${i}' has expected document`); - assert.strictEqual(actual.range.start.line, expected.line, `Definition '${i}' has expected start line`); - assert.strictEqual(actual.range.end.line, expected.line, `Definition '${i}' has expected end line`); - if (typeof expected.startCharacter !== 'undefined') { - assert.strictEqual(actual.range.start.character, expected.startCharacter, `Definition '${i}' has expected start character`); - } - if (typeof expected.endCharacter !== 'undefined') { - assert.strictEqual(actual.range.end.character, expected.endCharacter, `Definition '${i}' has expected end character`); - } - } -} - -suite('markdown: Go to definition', () => { - test('Should not return definition when on link text', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `[ref](#abc)`, - `[ref]: http://example.com`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const defs = await getDefinition(store, doc, new vscode.Position(0, 1), workspace); - assert.deepStrictEqual(defs, undefined); - })); - - test('Should find definition links within file from link', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `[link 1][abc]`, // trigger here - ``, - `[abc]: https://example.com`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const defs = await getDefinition(store, doc, new vscode.Position(0, 12), workspace); - assertDefinitionsEqual(defs!, - { uri: docUri, line: 2 }, - ); - })); - - test('Should find definition links using shorthand', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `[ref]`, // trigger 1 - ``, - `[yes][ref]`, // trigger 2 - ``, - `[ref]: /Hello.md` // trigger 3 - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - { - const defs = await getDefinition(store, doc, new vscode.Position(0, 2), workspace); - assertDefinitionsEqual(defs!, - { uri: docUri, line: 4 }, - ); - } - { - const defs = await getDefinition(store, doc, new vscode.Position(2, 7), workspace); - assertDefinitionsEqual(defs!, - { uri: docUri, line: 4 }, - ); - } - { - const defs = await getDefinition(store, doc, new vscode.Position(4, 2), workspace); - assertDefinitionsEqual(defs!, - { uri: docUri, line: 4 }, - ); - } - })); - - test('Should find definition links within file from definition', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `[link 1][abc]`, - ``, - `[abc]: https://example.com`, // trigger here - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const defs = await getDefinition(store, doc, new vscode.Position(2, 3), workspace); - assertDefinitionsEqual(defs!, - { uri: docUri, line: 2 }, - ); - })); - - test('Should not find definition links across files', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `[link 1][abc]`, - ``, - `[abc]: https://example.com`, - )); - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(workspacePath('other.md'), joinLines( - `[link 1][abc]`, - ``, - `[abc]: https://example.com?bad` - )) - ])); - - const defs = await getDefinition(store, doc, new vscode.Position(0, 12), workspace); - assertDefinitionsEqual(defs!, - { uri: docUri, line: 2 }, - ); - })); -}); diff --git a/extensions/markdown-language-features/src/test/diagnostic.test.ts b/extensions/markdown-language-features/src/test/diagnostic.test.ts deleted file mode 100644 index 020e745a2d3..00000000000 --- a/extensions/markdown-language-features/src/test/diagnostic.test.ts +++ /dev/null @@ -1,591 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { DiagnosticCollectionReporter, DiagnosticComputer, DiagnosticConfiguration, DiagnosticLevel, DiagnosticManager, DiagnosticOptions, DiagnosticReporter } from '../languageFeatures/diagnostics'; -import { MdLinkProvider } from '../languageFeatures/documentLinks'; -import { MdReferencesProvider } from '../languageFeatures/references'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; -import { noopToken } from '../util/cancellation'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { ResourceMap } from '../util/resourceMap'; -import { IMdWorkspace } from '../workspace'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { assertRangeEqual, joinLines, withStore, workspacePath } from './util'; - -const defaultDiagnosticsOptions = Object.freeze({ - enabled: true, - validateFileLinks: DiagnosticLevel.warning, - validateMarkdownFileLinkFragments: undefined, - validateFragmentLinks: DiagnosticLevel.warning, - validateReferences: DiagnosticLevel.warning, - ignoreLinks: [], -}); - -async function getComputedDiagnostics(store: DisposableStore, doc: InMemoryDocument, workspace: IMdWorkspace, options: Partial = {}): Promise { - const engine = createNewMarkdownEngine(); - const linkProvider = store.add(new MdLinkProvider(engine, workspace, nulLogger)); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const computer = new DiagnosticComputer(workspace, linkProvider, tocProvider); - return ( - await computer.getDiagnostics(doc, { ...defaultDiagnosticsOptions, ...options, }, noopToken) - ).diagnostics; -} - -function assertDiagnosticsEqual(actual: readonly vscode.Diagnostic[], expectedRanges: readonly vscode.Range[]) { - assert.strictEqual(actual.length, expectedRanges.length, "Diagnostic count equal"); - - for (let i = 0; i < actual.length; ++i) { - assertRangeEqual(actual[i].range, expectedRanges[i], `Range ${i} to be equal`); - } -} - -function orderDiagnosticsByRange(diagnostics: Iterable): readonly vscode.Diagnostic[] { - return Array.from(diagnostics).sort((a, b) => a.range.start.compareTo(b.range.start)); -} - -class MemoryDiagnosticConfiguration implements DiagnosticConfiguration { - - private readonly _onDidChange = new vscode.EventEmitter(); - public readonly onDidChange = this._onDidChange.event; - - private _options: Partial; - - constructor(options: Partial) { - this._options = options; - } - - public getOptions(_resource: vscode.Uri): DiagnosticOptions { - return { - ...defaultDiagnosticsOptions, - ...this._options, - }; - } - - public update(newOptions: Partial) { - this._options = newOptions; - this._onDidChange.fire(); - } -} - -class MemoryDiagnosticReporter extends DiagnosticReporter { - - private readonly diagnostics = new ResourceMap(); - - constructor( - private readonly workspace: InMemoryMdWorkspace, - ) { - super(); - } - - override dispose(): void { - super.clear(); - this.clear(); - } - - override clear(): void { - super.clear(); - this.diagnostics.clear(); - } - - set(uri: vscode.Uri, diagnostics: readonly vscode.Diagnostic[]): void { - this.diagnostics.set(uri, diagnostics); - } - - isOpen(_uri: vscode.Uri): boolean { - return true; - } - - delete(uri: vscode.Uri): void { - this.diagnostics.delete(uri); - } - - get(uri: vscode.Uri): readonly vscode.Diagnostic[] { - return orderDiagnosticsByRange(this.diagnostics.get(uri) ?? []); - } - - getOpenDocuments(): ITextDocument[] { - return this.workspace.values(); - } -} - -suite('markdown: Diagnostic Computer', () => { - - test('Should not return any diagnostics for empty document', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `text`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const diagnostics = await getComputedDiagnostics(store, doc, workspace); - assert.deepStrictEqual(diagnostics, []); - })); - - test('Should generate diagnostic for link to file that does not exist', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `[bad](/no/such/file.md)`, - `[good](/doc.md)`, - `[good-ref]: /doc.md`, - `[bad-ref]: /no/such/file.md`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const diagnostics = await getComputedDiagnostics(store, doc, workspace); - assertDiagnosticsEqual(diagnostics, [ - new vscode.Range(0, 6, 0, 22), - new vscode.Range(3, 11, 3, 27), - ]); - })); - - test('Should generate diagnostics for links to header that does not exist in current file', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `[good](#good-header)`, - `# Good Header`, - `[bad](#no-such-header)`, - `[good](#good-header)`, - `[good-ref]: #good-header`, - `[bad-ref]: #no-such-header`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const diagnostics = await getComputedDiagnostics(store, doc, workspace); - assertDiagnosticsEqual(diagnostics, [ - new vscode.Range(2, 6, 2, 21), - new vscode.Range(5, 11, 5, 26), - ]); - })); - - test('Should generate diagnostics for links to non-existent headers in other files', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `# My header`, - `[good](#my-header)`, - `[good](/doc1.md#my-header)`, - `[good](doc1.md#my-header)`, - `[good](/doc2.md#other-header)`, - `[bad](/doc2.md#no-such-other-header)`, - )); - - const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines( - `# Other header`, - )); - - const diagnostics = await getComputedDiagnostics(store, doc1, new InMemoryMdWorkspace([doc1, doc2])); - assertDiagnosticsEqual(diagnostics, [ - new vscode.Range(5, 14, 5, 35), - ]); - })); - - test('Should support links both with and without .md file extension', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `# My header`, - `[good](#my-header)`, - `[good](/doc.md#my-header)`, - `[good](doc.md#my-header)`, - `[good](/doc#my-header)`, - `[good](doc#my-header)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const diagnostics = await getComputedDiagnostics(store, doc, workspace); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('Should generate diagnostics for non-existent link reference', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `[good link][good]`, - `[bad link][no-such]`, - ``, - `[good]: http://example.com`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const diagnostics = await getComputedDiagnostics(store, doc, workspace); - assertDiagnosticsEqual(diagnostics, [ - new vscode.Range(1, 11, 1, 18), - ]); - })); - - test('Should not generate diagnostics when validate is disabled', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `[text](#no-such-header)`, - `[text][no-such-ref]`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1])); - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, new MemoryDiagnosticConfiguration({ enabled: false }).getOptions(doc1.uri)); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('Should not generate diagnostics for email autolink', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `a c`, - )); - - const diagnostics = await getComputedDiagnostics(store, doc1, new InMemoryMdWorkspace([doc1])); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('Should not generate diagnostics for html tag that looks like an autolink', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `a b c`, - `a b c`, - )); - - const diagnostics = await getComputedDiagnostics(store, doc1, new InMemoryMdWorkspace([doc1])); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('Should allow ignoring invalid file link using glob', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `[text](/no-such-file)`, - `![img](/no-such-file)`, - `[text]: /no-such-file`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1])); - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/no-such-file'] }); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('Should be able to disable fragment validation for external files', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `![i](/doc2.md#no-such)`, - )); - const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines('')); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); - - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { validateMarkdownFileLinkFragments: DiagnosticLevel.ignore }); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('Disabling own fragment validation should also disable path fragment validation by default', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `[b](#no-head)`, - `![i](/doc2.md#no-such)`, - )); - const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines('')); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); - - { - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { validateFragmentLinks: DiagnosticLevel.ignore }); - assertDiagnosticsEqual(diagnostics, []); - } - { - // But we should be able to override the default - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { validateFragmentLinks: DiagnosticLevel.ignore, validateMarkdownFileLinkFragments: DiagnosticLevel.warning }); - assertDiagnosticsEqual(diagnostics, [ - new vscode.Range(1, 13, 1, 21), - ]); - } - })); - - test('ignoreLinks should allow skipping link to non-existent file', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `[text](/no-such-file#header)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1])); - - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/no-such-file'] }); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('ignoreLinks should not consider link fragment', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `[text](/no-such-file#header)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1])); - - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/no-such-file'] }); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('ignoreLinks should support globs', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `![i](/images/aaa.png)`, - `![i](/images/sub/bbb.png)`, - `![i](/images/sub/sub2/ccc.png)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1])); - - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/images/**/*.png'] }); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('ignoreLinks should support ignoring header', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `![i](#no-such)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1])); - - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['#no-such'] }); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('ignoreLinks should support ignoring header in file', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `![i](/doc2.md#no-such)`, - )); - const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines('')); - const workspace = store.add(new InMemoryMdWorkspace([doc1, doc2])); - - { - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/doc2.md#no-such'] }); - assertDiagnosticsEqual(diagnostics, []); - } - { - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/doc2.md#*'] }); - assertDiagnosticsEqual(diagnostics, []); - } - })); - - test('ignoreLinks should support ignore header links if file is ignored', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `![i](/doc2.md#no-such)`, - )); - const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines('')); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); - - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/doc2.md'] }); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('Should not detect checkboxes as invalid links', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `- [x]`, - `- [X]`, - `- [ ]`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1])); - - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/doc2.md'] }); - assertDiagnosticsEqual(diagnostics, []); - })); - - test('Should detect invalid links with titles', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc1.md'), joinLines( - `[link]( "text")`, - `[link]( 'text')`, - `[link]( (text))`, - `[link](no-such.md "text")`, - `[link](no-such.md 'text')`, - `[link](no-such.md (text))`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const diagnostics = await getComputedDiagnostics(store, doc, workspace); - assertDiagnosticsEqual(diagnostics, [ - new vscode.Range(0, 8, 0, 18), - new vscode.Range(1, 8, 1, 18), - new vscode.Range(2, 8, 2, 18), - new vscode.Range(3, 7, 3, 17), - new vscode.Range(4, 7, 4, 17), - new vscode.Range(5, 7, 5, 17), - ]); - })); - - test('Should generate diagnostics for non-existent header using file link to own file', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('sub', 'doc.md'), joinLines( - `[bad](doc.md#no-such)`, - `[bad](doc#no-such)`, - `[bad](/sub/doc.md#no-such)`, - `[bad](/sub/doc#no-such)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const diagnostics = await getComputedDiagnostics(store, doc, workspace); - assertDiagnosticsEqual(orderDiagnosticsByRange(diagnostics), [ - new vscode.Range(0, 12, 0, 20), - new vscode.Range(1, 9, 1, 17), - new vscode.Range(2, 17, 2, 25), - new vscode.Range(3, 14, 3, 22), - ]); - })); - - test('Own header link using file path link should be controlled by "validateMarkdownFileLinkFragments" instead of "validateFragmentLinks"', withStore(async (store) => { - const doc1 = new InMemoryDocument(workspacePath('sub', 'doc.md'), joinLines( - `[bad](doc.md#no-such)`, - `[bad](doc#no-such)`, - `[bad](/sub/doc.md#no-such)`, - `[bad](/sub/doc#no-such)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1])); - - const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { - validateFragmentLinks: DiagnosticLevel.ignore, - validateMarkdownFileLinkFragments: DiagnosticLevel.warning, - }); - assertDiagnosticsEqual(orderDiagnosticsByRange(diagnostics), [ - new vscode.Range(0, 12, 0, 20), - new vscode.Range(1, 9, 1, 17), - new vscode.Range(2, 17, 2, 25), - new vscode.Range(3, 14, 3, 22), - ]); - })); -}); - -suite('Markdown: Diagnostics manager', () => { - - function createDiagnosticsManager( - store: DisposableStore, - workspace: IMdWorkspace, - configuration = new MemoryDiagnosticConfiguration({}), - reporter: DiagnosticReporter = new DiagnosticCollectionReporter(), - ) { - const engine = createNewMarkdownEngine(); - const linkProvider = store.add(new MdLinkProvider(engine, workspace, nulLogger)); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const referencesProvider = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); - const manager = store.add(new DiagnosticManager( - workspace, - new DiagnosticComputer(workspace, linkProvider, tocProvider), - configuration, - reporter, - referencesProvider, - tocProvider, - nulLogger, - 0)); - return manager; - } - - test('Changing enable/disable should recompute diagnostics', withStore(async (store) => { - const doc1Uri = workspacePath('doc1.md'); - const doc2Uri = workspacePath('doc2.md'); - const workspace = store.add(new InMemoryMdWorkspace([ - new InMemoryDocument(doc1Uri, joinLines( - `[text](#no-such-1)`, - )), - new InMemoryDocument(doc2Uri, joinLines( - `[text](#no-such-2)`, - )) - ])); - - const reporter = store.add(new MemoryDiagnosticReporter(workspace)); - const config = new MemoryDiagnosticConfiguration({ enabled: true }); - - const manager = createDiagnosticsManager(store, workspace, config, reporter); - await manager.ready; - - // Check initial state (Enabled) - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), [ - new vscode.Range(0, 7, 0, 17), - ]); - assertDiagnosticsEqual(reporter.get(doc2Uri), [ - new vscode.Range(0, 7, 0, 17), - ]); - - // Disable - config.update({ enabled: false }); - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), []); - assertDiagnosticsEqual(reporter.get(doc2Uri), []); - - // Enable - config.update({ enabled: true }); - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), [ - new vscode.Range(0, 7, 0, 17), - ]); - assertDiagnosticsEqual(reporter.get(doc2Uri), [ - new vscode.Range(0, 7, 0, 17), - ]); - })); - - test('Should revalidate linked files when header changes', withStore(async (store) => { - const doc1Uri = workspacePath('doc1.md'); - const doc1 = new InMemoryDocument(doc1Uri, joinLines( - `[text](#no-such)`, - `[text](/doc2.md#header)`, - )); - const doc2Uri = workspacePath('doc2.md'); - const doc2 = new InMemoryDocument(doc2Uri, joinLines( - `# Header`, - `[text](#header)`, - `[text](#no-such-2)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1, doc2])); - const reporter = store.add(new MemoryDiagnosticReporter(workspace)); - - const manager = createDiagnosticsManager(store, workspace, new MemoryDiagnosticConfiguration({}), reporter); - await manager.ready; - - // Check initial state - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), [ - new vscode.Range(0, 7, 0, 15), - ]); - assertDiagnosticsEqual(reporter.get(doc2Uri), [ - new vscode.Range(2, 7, 2, 17), - ]); - - // Edit header - workspace.updateDocument(new InMemoryDocument(doc2Uri, joinLines( - `# new header`, - `[text](#new-header)`, - `[text](#no-such-2)`, - ))); - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), [ - new vscode.Range(0, 7, 0, 15), - new vscode.Range(1, 15, 1, 22), - ]); - assertDiagnosticsEqual(reporter.get(doc2Uri), [ - new vscode.Range(2, 7, 2, 17), - ]); - - // Revert to original file - workspace.updateDocument(new InMemoryDocument(doc2Uri, joinLines( - `# header`, - `[text](#header)`, - `[text](#no-such-2)`, - ))); - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), [ - new vscode.Range(0, 7, 0, 15) - ]); - assertDiagnosticsEqual(reporter.get(doc2Uri), [ - new vscode.Range(2, 7, 2, 17), - ]); - })); - - test('Should revalidate linked files when file is deleted/created', withStore(async (store) => { - const doc1Uri = workspacePath('doc1.md'); - const doc1 = new InMemoryDocument(doc1Uri, joinLines( - `[text](/doc2.md)`, - `[text](/doc2.md#header)`, - )); - const doc2Uri = workspacePath('doc2.md'); - const doc2 = new InMemoryDocument(doc2Uri, joinLines( - `# Header` - )); - const workspace = store.add(new InMemoryMdWorkspace([doc1, doc2])); - const reporter = store.add(new MemoryDiagnosticReporter(workspace)); - - const manager = createDiagnosticsManager(store, workspace, new MemoryDiagnosticConfiguration({}), reporter); - await manager.ready; - - // Check initial state - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), []); - - // Edit header - workspace.deleteDocument(doc2Uri); - - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), [ - new vscode.Range(0, 7, 0, 15), - new vscode.Range(1, 7, 1, 22), - ]); - - // Revert to original file - workspace.createDocument(doc2); - await reporter.waitPendingWork(); - assertDiagnosticsEqual(reporter.get(doc1Uri), []); - })); -}); diff --git a/extensions/markdown-language-features/src/test/documentInfoCache.test.ts b/extensions/markdown-language-features/src/test/documentInfoCache.test.ts deleted file mode 100644 index a1b291aee0b..00000000000 --- a/extensions/markdown-language-features/src/test/documentInfoCache.test.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 * as assert from 'assert'; -import 'mocha'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { MdDocumentInfoCache } from '../util/workspaceCache'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { workspacePath } from './util'; - -suite('DocumentInfoCache', () => { - test('Repeated calls should only compute value once', async () => { - const doc = workspacePath('doc.md'); - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(doc, '') - ]); - - let i = 0; - const cache = new MdDocumentInfoCache(workspace, async () => { - return ++i; - }); - - const a = cache.get(doc); - const b = cache.get(doc); - - assert.strictEqual(await a, 1); - assert.strictEqual(i, 1); - assert.strictEqual(await b, 1); - assert.strictEqual(i, 1); - }); -}); diff --git a/extensions/markdown-language-features/src/test/documentLink.test.ts b/extensions/markdown-language-features/src/test/documentLink.test.ts index 7c280a82bdf..37fe52e3dfb 100644 --- a/extensions/markdown-language-features/src/test/documentLink.test.ts +++ b/extensions/markdown-language-features/src/test/documentLink.test.ts @@ -24,7 +24,7 @@ function workspaceFile(...segments: string[]) { async function getLinksForFile(file: vscode.Uri): Promise { debugLog('getting links', file.toString(), Date.now()); - const r = (await vscode.commands.executeCommand('vscode.executeLinkProvider', file))!; + const r = (await vscode.commands.executeCommand('vscode.executeLinkProvider', file, /*linkResolveCount*/ 100))!; debugLog('got links', file.toString(), Date.now()); return r; } @@ -134,7 +134,7 @@ async function getLinksForFile(file: vscode.Uri): Promise } }); - test('Should navigate to fragment within current untitled file', async () => { + test('Should navigate to fragment within current untitled file', async () => { // TODO: skip for now for ls migration const testFile = workspaceFile('x.md').with({ scheme: 'untitled' }); await withFileContents(testFile, joinLines( '[](#second)', @@ -171,7 +171,7 @@ async function withFileContents(file: vscode.Uri, contents: string): Promise { - - function getLinksForFile(fileContents: string): Promise { - const doc = new InMemoryDocument(workspacePath('x.md'), fileContents); - const engine = createNewMarkdownEngine(); - const linkProvider = new MdLinkComputer(engine); - return linkProvider.getAllLinks(doc, noopToken); - } - - function assertLinksEqual(actualLinks: readonly MdLink[], expected: ReadonlyArray) { - assert.strictEqual(actualLinks.length, expected.length); - - for (let i = 0; i < actualLinks.length; ++i) { - const exp = expected[i]; - if ('range' in exp) { - assertRangeEqual(actualLinks[i].source.hrefRange, exp.range, `Range ${i} to be equal`); - assert.strictEqual(actualLinks[i].source.hrefText, exp.sourceText, `Source text ${i} to be equal`); - } else { - assertRangeEqual(actualLinks[i].source.hrefRange, exp, `Range ${i} to be equal`); - } - } - } - - test('Should not return anything for empty document', async () => { - const links = await getLinksForFile(''); - assertLinksEqual(links, []); - }); - - test('Should not return anything for simple document without links', async () => { - const links = await getLinksForFile(joinLines( - '# a', - 'fdasfdfsafsa', - )); - assertLinksEqual(links, []); - }); - - test('Should detect basic http links', async () => { - const links = await getLinksForFile('a [b](https://example.com) c'); - assertLinksEqual(links, [ - new vscode.Range(0, 6, 0, 25) - ]); - }); - - test('Should detect basic workspace links', async () => { - { - const links = await getLinksForFile('a [b](./file) c'); - assertLinksEqual(links, [ - new vscode.Range(0, 6, 0, 12) - ]); - } - { - const links = await getLinksForFile('a [b](file.png) c'); - assertLinksEqual(links, [ - new vscode.Range(0, 6, 0, 14) - ]); - } - }); - - test('Should detect links with title', async () => { - const links = await getLinksForFile('a [b](https://example.com "abc") c'); - assertLinksEqual(links, [ - new vscode.Range(0, 6, 0, 25) - ]); - }); - - test('Should handle links with escaped characters in name (#35245)', async () => { - const links = await getLinksForFile('a [b\\]](./file)'); - assertLinksEqual(links, [ - new vscode.Range(0, 8, 0, 14) - ]); - }); - - test('Should handle links with balanced parens', async () => { - { - const links = await getLinksForFile('a [b](https://example.com/a()c) c'); - assertLinksEqual(links, [ - new vscode.Range(0, 6, 0, 30) - ]); - } - { - const links = await getLinksForFile('a [b](https://example.com/a(b)c) c'); - assertLinksEqual(links, [ - new vscode.Range(0, 6, 0, 31) - ]); - } - { - // #49011 - const links = await getLinksForFile('[A link](http://ThisUrlhasParens/A_link(in_parens))'); - assertLinksEqual(links, [ - new vscode.Range(0, 9, 0, 50) - ]); - } - }); - - test('Should ignore bracketed text inside link title (#150921)', async () => { - { - const links = await getLinksForFile('[some [inner] in title](link)'); - assertLinksEqual(links, [ - new vscode.Range(0, 24, 0, 28), - ]); - } - { - const links = await getLinksForFile('[some [inner] in title]()'); - assertLinksEqual(links, [ - new vscode.Range(0, 25, 0, 29), - ]); - } - { - const links = await getLinksForFile('[some [inner with space] in title](link)'); - assertLinksEqual(links, [ - new vscode.Range(0, 35, 0, 39), - ]); - } - }); - - test('Should handle two links without space', async () => { - const links = await getLinksForFile('a ([test](test)[test2](test2)) c'); - assertLinksEqual(links, [ - new vscode.Range(0, 10, 0, 14), - new vscode.Range(0, 23, 0, 28) - ]); - }); - - test('should handle hyperlinked images (#49238)', async () => { - { - const links = await getLinksForFile('[![alt text](image.jpg)](https://example.com)'); - assertLinksEqual(links, [ - new vscode.Range(0, 25, 0, 44), - new vscode.Range(0, 13, 0, 22), - ]); - } - { - const links = await getLinksForFile('[![a]( whitespace.jpg )]( https://whitespace.com )'); - assertLinksEqual(links, [ - new vscode.Range(0, 26, 0, 48), - new vscode.Range(0, 7, 0, 21), - ]); - } - { - const links = await getLinksForFile('[![a](img1.jpg)](file1.txt) text [![a](img2.jpg)](file2.txt)'); - assertLinksEqual(links, [ - new vscode.Range(0, 17, 0, 26), - new vscode.Range(0, 6, 0, 14), - new vscode.Range(0, 50, 0, 59), - new vscode.Range(0, 39, 0, 47), - ]); - } - }); - - test('Should not consider link references starting with ^ character valid (#107471)', async () => { - const links = await getLinksForFile('[^reference]: https://example.com'); - assertLinksEqual(links, []); - }); - - test('Should find definitions links with spaces in angle brackets (#136073)', async () => { - const links = await getLinksForFile(joinLines( - '[a]: ', - '[b]: ', - )); - - assertLinksEqual(links, [ - { range: new vscode.Range(0, 6, 0, 9), sourceText: 'b c' }, - { range: new vscode.Range(1, 6, 1, 8), sourceText: 'cd' }, - ]); - }); - - test('Should only find one link for reference sources [a]: source (#141285)', async () => { - const links = await getLinksForFile(joinLines( - '[Works]: https://example.com', - )); - - assertLinksEqual(links, [ - { range: new vscode.Range(0, 9, 0, 28), sourceText: 'https://example.com' }, - ]); - }); - - test('Should find reference link shorthand (#141285)', async () => { - const links = await getLinksForFile(joinLines( - '[ref]', - '[ref]: https://example.com', - )); - assertLinksEqual(links, [ - { range: new vscode.Range(0, 1, 0, 4), sourceText: 'ref' }, - { range: new vscode.Range(1, 7, 1, 26), sourceText: 'https://example.com' }, - ]); - }); - - test('Should find reference link shorthand using empty closing brackets (#141285)', async () => { - const links = await getLinksForFile(joinLines( - '[ref][]', - )); - assertLinksEqual(links, [ - new vscode.Range(0, 1, 0, 4), - ]); - }); - - test.skip('Should find reference link shorthand for link with space in label (#141285)', async () => { - const links = await getLinksForFile(joinLines( - '[ref with space]', - )); - assertLinksEqual(links, [ - new vscode.Range(0, 7, 0, 26), - ]); - }); - - test('Should not include reference links with escaped leading brackets', async () => { - const links = await getLinksForFile(joinLines( - `\\[bad link][good]`, - `\\[good]`, - `[good]: http://example.com`, - )); - assertLinksEqual(links, [ - new vscode.Range(2, 8, 2, 26) // Should only find the definition - ]); - }); - - test('Should not consider links in code fenced with backticks', async () => { - const links = await getLinksForFile(joinLines( - '```', - '[b](https://example.com)', - '```')); - assertLinksEqual(links, []); - }); - - test('Should not consider links in code fenced with tilde', async () => { - const links = await getLinksForFile(joinLines( - '~~~', - '[b](https://example.com)', - '~~~')); - assertLinksEqual(links, []); - }); - - test('Should not consider links in indented code', async () => { - const links = await getLinksForFile(' [b](https://example.com)'); - assertLinksEqual(links, []); - }); - - test('Should not consider links in inline code span', async () => { - const links = await getLinksForFile('`[b](https://example.com)`'); - assertLinksEqual(links, []); - }); - - test('Should not consider links with code span inside', async () => { - const links = await getLinksForFile('[li`nk](https://example.com`)'); - assertLinksEqual(links, []); - }); - - test('Should not consider links in multiline inline code span', async () => { - const links = await getLinksForFile(joinLines( - '`` ', - '[b](https://example.com)', - '``')); - assertLinksEqual(links, []); - }); - - test('Should not consider link references in code fenced with backticks (#146714)', async () => { - const links = await getLinksForFile(joinLines( - '```', - '[a] [bb]', - '```')); - assertLinksEqual(links, []); - }); - - test('Should not consider reference sources in code fenced with backticks (#146714)', async () => { - const links = await getLinksForFile(joinLines( - '```', - '[a]: http://example.com;', - '[b]: ;', - '[c]: (http://example.com);', - '```')); - assertLinksEqual(links, []); - }); - - test('Should not consider links in multiline inline code span between between text', async () => { - const links = await getLinksForFile(joinLines( - '[b](https://1.com) `[b](https://2.com)', - '[b](https://3.com) ` [b](https://4.com)')); - - assertLinksEqual(links, [ - new vscode.Range(0, 4, 0, 17), - new vscode.Range(1, 25, 1, 38), - ]); - }); - - test('Should not consider links in multiline inline code span with new line after the first backtick', async () => { - const links = await getLinksForFile(joinLines( - '`', - '[b](https://example.com)`')); - assertLinksEqual(links, []); - }); - - test('Should not miss links in invalid multiline inline code span', async () => { - const links = await getLinksForFile(joinLines( - '`` ', - '', - '[b](https://example.com)', - '', - '``')); - assertLinksEqual(links, [ - new vscode.Range(2, 4, 2, 23) - ]); - }); - - test('Should find autolinks', async () => { - const links = await getLinksForFile('pre post'); - assertLinksEqual(links, [ - new vscode.Range(0, 5, 0, 23) - ]); - }); - - test('Should not detect links inside html comment blocks', async () => { - const links = await getLinksForFile(joinLines( - ``, - ``, - ``, - ``, - ``, - ``, - ``, - ``, - ``, - )); - assertLinksEqual(links, []); - }); - - test.skip('Should not detect links inside inline html comments', async () => { - // See #149678 - const links = await getLinksForFile(joinLines( - `text text`, - `text text`, - `text text`, - ``, - `text text`, - ``, - `text text`, - ``, - `text text`, - )); - assertLinksEqual(links, []); - }); - - test('Should not mark checkboxes as links', async () => { - const links = await getLinksForFile(joinLines( - '- [x]', - '- [X]', - '- [ ]', - '* [x]', - '* [X]', - '* [ ]', - ``, - `[x]: http://example.com` - )); - assertLinksEqual(links, [ - new vscode.Range(7, 5, 7, 23) - ]); - }); - - test('Should still find links on line with checkbox', async () => { - const links = await getLinksForFile(joinLines( - '- [x] [x]', - '- [X] [x]', - '- [] [x]', - ``, - `[x]: http://example.com` - )); - - assertLinksEqual(links, [ - new vscode.Range(0, 7, 0, 8), - new vscode.Range(1, 7, 1, 8), - new vscode.Range(2, 6, 2, 7), - new vscode.Range(4, 5, 4, 23), - ]); - }); - - test('Should find link only within angle brackets.', async () => { - const links = await getLinksForFile(joinLines( - `[link]()` - )); - assertLinksEqual(links, [new vscode.Range(0, 8, 0, 12)]); - }); - - test('Should find link within angle brackets even with link title.', async () => { - const links = await getLinksForFile(joinLines( - `[link]( "test title")` - )); - assertLinksEqual(links, [new vscode.Range(0, 8, 0, 12)]); - }); - - test('Should find link within angle brackets even with surrounding spaces.', async () => { - const links = await getLinksForFile(joinLines( - `[link]( )` - )); - assertLinksEqual(links, [new vscode.Range(0, 9, 0, 13)]); - }); - - test('Should find link within angle brackets for image hyperlinks.', async () => { - const links = await getLinksForFile(joinLines( - `![link]()` - )); - assertLinksEqual(links, [new vscode.Range(0, 9, 0, 13)]); - }); - - test('Should find link with spaces in angle brackets for image hyperlinks with titles.', async () => { - const links = await getLinksForFile(joinLines( - `![link](< path > "test")` - )); - assertLinksEqual(links, [new vscode.Range(0, 9, 0, 15)]); - }); - - - test('Should not find link due to incorrect angle bracket notation or usage.', async () => { - const links = await getLinksForFile(joinLines( - `[link]( path>)`, - `[link](> path)`, - )); - assertLinksEqual(links, []); - }); - - test('Should find link within angle brackets even with space inside link.', async () => { - - const links = await getLinksForFile(joinLines( - `[link]()` - )); - - assertLinksEqual(links, [new vscode.Range(0, 8, 0, 13)]); - }); - - test('Should find links with titles', async () => { - const links = await getLinksForFile(joinLines( - `[link]( "text")`, - `[link]( 'text')`, - `[link]( (text))`, - `[link](no-such.md "text")`, - `[link](no-such.md 'text')`, - `[link](no-such.md (text))`, - )); - assertLinksEqual(links, [ - new vscode.Range(0, 8, 0, 18), - new vscode.Range(1, 8, 1, 18), - new vscode.Range(2, 8, 2, 18), - new vscode.Range(3, 7, 3, 17), - new vscode.Range(4, 7, 4, 17), - new vscode.Range(5, 7, 5, 17), - ]); - }); - - test('Should not include link with empty angle bracket', async () => { - const links = await getLinksForFile(joinLines( - `[](<>)`, - `[link](<>)`, - `[link](<> "text")`, - `[link](<> 'text')`, - `[link](<> (text))`, - )); - assertLinksEqual(links, []); - }); -}); - - -suite('Markdown: VS Code DocumentLinkProvider', () => { - - function getLinksForFile(fileContents: string) { - const doc = new InMemoryDocument(workspacePath('x.md'), fileContents); - const workspace = new InMemoryMdWorkspace([doc]); - - const engine = createNewMarkdownEngine(); - const linkProvider = new MdLinkProvider(engine, workspace, nulLogger); - const provider = new MdVsCodeLinkProvider(linkProvider); - return provider.provideDocumentLinks(doc, noopToken); - } - - function assertLinksEqual(actualLinks: readonly vscode.DocumentLink[], expectedRanges: readonly vscode.Range[]) { - assert.strictEqual(actualLinks.length, expectedRanges.length); - - for (let i = 0; i < actualLinks.length; ++i) { - assertRangeEqual(actualLinks[i].range, expectedRanges[i], `Range ${i} to be equal`); - } - } - - test('Should include defined reference links (#141285)', async () => { - const links = await getLinksForFile(joinLines( - '[ref]', - '[ref][]', - '[ref][ref]', - '', - '[ref]: http://example.com' - )); - assertLinksEqual(links, [ - new vscode.Range(0, 1, 0, 4), - new vscode.Range(1, 1, 1, 4), - new vscode.Range(2, 6, 2, 9), - new vscode.Range(4, 7, 4, 25), - ]); - }); - - test('Should not include reference link shorthand when definition does not exist (#141285)', async () => { - const links = await getLinksForFile('[ref]'); - assertLinksEqual(links, []); - }); -}); diff --git a/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts deleted file mode 100644 index c4570303868..00000000000 --- a/extensions/markdown-language-features/src/test/documentSymbolProvider.test.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 * as assert from 'assert'; -import 'mocha'; -import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbols'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { joinLines, withStore, workspacePath } from './util'; - - -function getSymbolsForFile(store: DisposableStore, fileContents: string) { - const doc = new InMemoryDocument(workspacePath('test.md'), fileContents); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const provider = new MdDocumentSymbolProvider(tocProvider, nulLogger); - return provider.provideDocumentSymbols(doc); -} - -suite('Markdown: DocumentSymbolProvider', () => { - test('Should not return anything for empty document', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, ''); - assert.strictEqual(symbols.length, 0); - })); - - test('Should not return anything for document with no headers', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `a`, - `a`, - )); - assert.strictEqual(symbols.length, 0); - })); - - test('Should not return anything for document with # but no real headers', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `a#a`, - `a#`, - )); - assert.strictEqual(symbols.length, 0); - })); - - test('Should return single symbol for single header', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, '# h'); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '# h'); - })); - - test('Should not care about symbol level for single header', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, '### h'); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '### h'); - })); - - test('Should put symbols of same level in flat list', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `## h`, - `## h2`, - )); - assert.strictEqual(symbols.length, 2); - assert.strictEqual(symbols[0].name, '## h'); - assert.strictEqual(symbols[1].name, '## h2'); - })); - - test('Should nest symbol of level - 1 under parent', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `# h`, - `## h2`, - `## h3`, - )); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '# h'); - assert.strictEqual(symbols[0].children.length, 2); - assert.strictEqual(symbols[0].children[0].name, '## h2'); - assert.strictEqual(symbols[0].children[1].name, '## h3'); - })); - - test('Should nest symbol of level - n under parent', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `# h`, - `#### h2`, - )); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '# h'); - assert.strictEqual(symbols[0].children.length, 1); - assert.strictEqual(symbols[0].children[0].name, '#### h2'); - })); - - test('Should flatten children where lower level occurs first', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `# h`, - `### h2`, - `## h3`, - )); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '# h'); - assert.strictEqual(symbols[0].children.length, 2); - assert.strictEqual(symbols[0].children[0].name, '### h2'); - assert.strictEqual(symbols[0].children[1].name, '## h3'); - })); - - test('Should handle line separator in file. Issue #63749', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `# A`, - `- foo`, - ``, - `# B`, - `- bar`, - )); - assert.strictEqual(symbols.length, 2); - assert.strictEqual(symbols[0].name, '# A'); - assert.strictEqual(symbols[1].name, '# B'); - })); -}); - diff --git a/extensions/markdown-language-features/src/test/engine.test.ts b/extensions/markdown-language-features/src/test/engine.test.ts index c0644ee20d9..424844d1ad7 100644 --- a/extensions/markdown-language-features/src/test/engine.test.ts +++ b/extensions/markdown-language-features/src/test/engine.test.ts @@ -30,22 +30,23 @@ suite('markdown.engine', () => { }); }); - suite('image-caching', () => { + suite.only('image-caching', () => { const input = '![](img.png) [](no-img.png) ![](http://example.org/img.png) ![](img.png) ![](./img2.png)'; test('Extracts all images', async () => { const engine = createNewMarkdownEngine(); - assert.deepStrictEqual((await engine.render(input)), { - html: '

' - + ' ' - + ' ' - + ' ' - + ' ' - + '' - + '

\n' - , - containingImages: [{ src: 'img.png' }, { src: 'http://example.org/img.png' }, { src: 'img.png' }, { src: './img2.png' }], - }); + const result = await engine.render(input); + assert.deepStrictEqual(result.html, + '

' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + + '

\n' + ); + + assert.deepStrictEqual([...result.containingImages], ['img.png', 'http://example.org/img.png', './img2.png']); }); }); }); diff --git a/extensions/markdown-language-features/src/test/fileReferences.test.ts b/extensions/markdown-language-features/src/test/fileReferences.test.ts deleted file mode 100644 index 3b49e7790ea..00000000000 --- a/extensions/markdown-language-features/src/test/fileReferences.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { MdReference, MdReferencesProvider } from '../languageFeatures/references'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { noopToken } from '../util/cancellation'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { IMdWorkspace } from '../workspace'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { joinLines, withStore, workspacePath } from './util'; - - -function getFileReferences(store: DisposableStore, resource: vscode.Uri, workspace: IMdWorkspace) { - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const computer = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); - return computer.getReferencesToFileInWorkspace(resource, noopToken); -} - -function assertReferencesEqual(actualRefs: readonly MdReference[], ...expectedRefs: { uri: vscode.Uri; line: number }[]) { - assert.strictEqual(actualRefs.length, expectedRefs.length, `Reference counts should match`); - - for (let i = 0; i < actualRefs.length; ++i) { - const actual = actualRefs[i].location; - const expected = expectedRefs[i]; - assert.strictEqual(actual.uri.toString(), expected.uri.toString(), `Ref '${i}' has expected document`); - assert.strictEqual(actual.range.start.line, expected.line, `Ref '${i}' has expected start line`); - assert.strictEqual(actual.range.end.line, expected.line, `Ref '${i}' has expected end line`); - } -} - -suite('markdown: find file references', () => { - - test('Should find basic references', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const otherUri = workspacePath('other.md'); - const workspace = store.add(new InMemoryMdWorkspace([ - new InMemoryDocument(docUri, joinLines( - `# header`, - `[link 1](./other.md)`, - `[link 2](./other.md)` - )), - new InMemoryDocument(otherUri, joinLines( - `# header`, - `pre`, - `[link 3](./other.md)`, - `post` - )), - ])); - - const refs = await getFileReferences(store, otherUri, workspace); - assertReferencesEqual(refs, - { uri: docUri, line: 1 }, - { uri: docUri, line: 2 }, - { uri: otherUri, line: 2 }, - ); - })); - - test('Should find references with and without file extensions', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const otherUri = workspacePath('other.md'); - const workspace = store.add(new InMemoryMdWorkspace([ - new InMemoryDocument(docUri, joinLines( - `# header`, - `[link 1](./other.md)`, - `[link 2](./other)` - )), - new InMemoryDocument(otherUri, joinLines( - `# header`, - `pre`, - `[link 3](./other.md)`, - `[link 4](./other)`, - `post` - )), - ])); - - const refs = await getFileReferences(store, otherUri, workspace); - assertReferencesEqual(refs, - { uri: docUri, line: 1 }, - { uri: docUri, line: 2 }, - { uri: otherUri, line: 2 }, - { uri: otherUri, line: 3 }, - ); - })); - - test('Should find references with headers on links', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const otherUri = workspacePath('other.md'); - const workspace = store.add(new InMemoryMdWorkspace([ - new InMemoryDocument(docUri, joinLines( - `# header`, - `[link 1](./other.md#sub-bla)`, - `[link 2](./other#sub-bla)` - )), - new InMemoryDocument(otherUri, joinLines( - `# header`, - `pre`, - `[link 3](./other.md#sub-bla)`, - `[link 4](./other#sub-bla)`, - `post` - )), - ])); - - const refs = await getFileReferences(store, otherUri, workspace); - assertReferencesEqual(refs, - { uri: docUri, line: 1 }, - { uri: docUri, line: 2 }, - { uri: otherUri, line: 2 }, - { uri: otherUri, line: 3 }, - ); - })); -}); diff --git a/extensions/markdown-language-features/src/test/foldingProvider.test.ts b/extensions/markdown-language-features/src/test/foldingProvider.test.ts deleted file mode 100644 index 85cbd84c581..00000000000 --- a/extensions/markdown-language-features/src/test/foldingProvider.test.ts +++ /dev/null @@ -1,230 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { MdFoldingProvider } from '../languageFeatures/folding'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { noopToken } from '../util/cancellation'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { joinLines, withStore } from './util'; - -const testFileName = vscode.Uri.file('test.md'); - -async function getFoldsForDocument(store: DisposableStore, contents: string) { - const doc = new InMemoryDocument(testFileName, contents); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const provider = new MdFoldingProvider(engine, tocProvider); - return provider.provideFoldingRanges(doc, {}, noopToken); -} - -suite('markdown.FoldingProvider', () => { - test('Should not return anything for empty document', withStore(async (store) => { - const folds = await getFoldsForDocument(store, ``); - assert.strictEqual(folds.length, 0); - })); - - test('Should not return anything for document without headers', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - `**b** afas`, - `a#b`, - `a`, - )); - assert.strictEqual(folds.length, 0); - })); - - test('Should fold from header to end of document', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - `# b`, - `c`, - `d`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - })); - - test('Should leave single newline before next header', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - ``, - `# a`, - `x`, - ``, - `# b`, - `y`, - )); - assert.strictEqual(folds.length, 2); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 2); - })); - - test('Should collapse multiple newlines to single newline before next header', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - ``, - `# a`, - `x`, - ``, - ``, - ``, - `# b`, - `y` - )); - assert.strictEqual(folds.length, 2); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 4); - })); - - test('Should not collapse if there is no newline before next header', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - ``, - `# a`, - `x`, - `# b`, - `y`, - )); - assert.strictEqual(folds.length, 2); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 2); - })); - - test('Should fold nested markers', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - ``, - `b`, - ``, - `b.a`, - ``, - `b`, - ``, - `b.b`, - ``, - `b`, - ``, - `a`, - )); - assert.strictEqual(folds.length, 3); - const [outer, first, second] = folds.sort((a, b) => a.start - b.start); - - assert.strictEqual(outer.start, 1); - assert.strictEqual(outer.end, 11); - assert.strictEqual(first.start, 3); - assert.strictEqual(first.end, 5); - assert.strictEqual(second.start, 7); - assert.strictEqual(second.end, 9); - })); - - test('Should fold from list to end of document', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - `- b`, - `c`, - `d`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - })); - - test('lists folds should span multiple lines of content', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - `- This list item\n spans multiple\n lines.`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - })); - - test('List should leave single blankline before new element', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `- a`, - `a`, - ``, - ``, - `b` - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 0); - assert.strictEqual(firstFold.end, 2); - })); - - test('Should fold fenced code blocks', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `~~~ts`, - `a`, - `~~~`, - `b`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 0); - assert.strictEqual(firstFold.end, 2); - })); - - test('Should fold fenced code blocks with yaml front matter', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `---`, - `title: bla`, - `---`, - ``, - `~~~ts`, - `a`, - `~~~`, - ``, - `a`, - `a`, - `b`, - `a`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 4); - assert.strictEqual(firstFold.end, 6); - })); - - test('Should fold html blocks', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `x`, - `
`, - ` fa`, - `
`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - })); - - test('Should fold html block comments', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `x`, - `` - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - assert.strictEqual(firstFold.kind, vscode.FoldingRangeKind.Comment); - })); -}); diff --git a/extensions/markdown-language-features/src/test/inMemoryWorkspace.ts b/extensions/markdown-language-features/src/test/inMemoryWorkspace.ts deleted file mode 100644 index a383a73335a..00000000000 --- a/extensions/markdown-language-features/src/test/inMemoryWorkspace.ts +++ /dev/null @@ -1,83 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import { ITextDocument } from '../types/textDocument'; -import { Disposable } from '../util/dispose'; -import { ResourceMap } from '../util/resourceMap'; -import { IMdWorkspace } from '../workspace'; - - -export class InMemoryMdWorkspace extends Disposable implements IMdWorkspace { - private readonly _documents = new ResourceMap(uri => uri.fsPath); - - constructor(documents: ITextDocument[]) { - super(); - for (const doc of documents) { - this._documents.set(doc.uri, doc); - } - } - - public values() { - return Array.from(this._documents.values()); - } - - public async getAllMarkdownDocuments() { - return this.values(); - } - - public async getOrLoadMarkdownDocument(resource: vscode.Uri): Promise { - return this._documents.get(resource); - } - - public hasMarkdownDocument(resolvedHrefPath: vscode.Uri): boolean { - return this._documents.has(resolvedHrefPath); - } - - public async pathExists(resource: vscode.Uri): Promise { - return this._documents.has(resource); - } - - public async readDirectory(resource: vscode.Uri): Promise<[string, vscode.FileType][]> { - const files = new Map(); - const pathPrefix = resource.fsPath + (resource.fsPath.endsWith('/') || resource.fsPath.endsWith('\\') ? '' : path.sep); - for (const doc of this._documents.values()) { - const path = doc.uri.fsPath; - if (path.startsWith(pathPrefix)) { - const parts = path.slice(pathPrefix.length).split(/\/|\\/g); - files.set(parts[0], parts.length > 1 ? vscode.FileType.Directory : vscode.FileType.File); - } - } - return Array.from(files.entries()); - } - - private readonly _onDidChangeMarkdownDocumentEmitter = this._register(new vscode.EventEmitter()); - public onDidChangeMarkdownDocument = this._onDidChangeMarkdownDocumentEmitter.event; - - private readonly _onDidCreateMarkdownDocumentEmitter = this._register(new vscode.EventEmitter()); - public onDidCreateMarkdownDocument = this._onDidCreateMarkdownDocumentEmitter.event; - - private readonly _onDidDeleteMarkdownDocumentEmitter = this._register(new vscode.EventEmitter()); - public onDidDeleteMarkdownDocument = this._onDidDeleteMarkdownDocumentEmitter.event; - - public updateDocument(document: ITextDocument) { - this._documents.set(document.uri, document); - this._onDidChangeMarkdownDocumentEmitter.fire(document); - } - - public createDocument(document: ITextDocument) { - assert.ok(!this._documents.has(document.uri)); - - this._documents.set(document.uri, document); - this._onDidCreateMarkdownDocumentEmitter.fire(document); - } - - public deleteDocument(resource: vscode.Uri) { - this._documents.delete(resource); - this._onDidDeleteMarkdownDocumentEmitter.fire(resource); - } -} diff --git a/extensions/markdown-language-features/src/test/pathCompletion.test.ts b/extensions/markdown-language-features/src/test/pathCompletion.test.ts deleted file mode 100644 index d124461f102..00000000000 --- a/extensions/markdown-language-features/src/test/pathCompletion.test.ts +++ /dev/null @@ -1,295 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { MdLinkProvider } from '../languageFeatures/documentLinks'; -import { MdVsCodePathCompletionProvider } from '../languageFeatures/pathCompletions'; -import { noopToken } from '../util/cancellation'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { IMdWorkspace } from '../workspace'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { CURSOR, getCursorPositions, joinLines, workspacePath } from './util'; - - -async function getCompletionsAtCursor(resource: vscode.Uri, fileContents: string, workspace?: IMdWorkspace) { - const doc = new InMemoryDocument(resource, fileContents); - - const engine = createNewMarkdownEngine(); - const ws = workspace ?? new InMemoryMdWorkspace([doc]); - const linkProvider = new MdLinkProvider(engine, ws, nulLogger); - const provider = new MdVsCodePathCompletionProvider(ws, engine, linkProvider); - const cursorPositions = getCursorPositions(fileContents, doc); - const completions = await provider.provideCompletionItems(doc, cursorPositions[0], noopToken, { - triggerCharacter: undefined, - triggerKind: vscode.CompletionTriggerKind.Invoke, - }); - - return completions.sort((a, b) => (a.label as string).localeCompare(b.label as string)); -} - -function assertCompletionsEqual(actual: readonly vscode.CompletionItem[], expected: readonly { label: string; insertText?: string }[]) { - assert.strictEqual(actual.length, expected.length, 'Completion counts should be equal'); - - for (let i = 0; i < actual.length; ++i) { - assert.strictEqual(actual[i].label, expected[i].label, `Completion labels ${i} should be equal`); - if (typeof expected[i].insertText !== 'undefined') { - assert.strictEqual(actual[i].insertText, expected[i].insertText, `Completion insert texts ${i} should be equal`); - } - } -} - -suite('Markdown: Path completions', () => { - - test('Should not return anything when triggered in empty doc', async () => { - const completions = await getCompletionsAtCursor(workspacePath('new.md'), `${CURSOR}`); - assertCompletionsEqual(completions, []); - }); - - test('Should return anchor completions', async () => { - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[](#${CURSOR}`, - ``, - `# A b C`, - `# x y Z`, - )); - - assertCompletionsEqual(completions, [ - { label: '#a-b-c' }, - { label: '#x-y-z' }, - ]); - }); - - test('Should not return suggestions for http links', async () => { - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[](http:${CURSOR}`, - ``, - `# http`, - `# http:`, - `# https:`, - )); - - assertCompletionsEqual(completions, []); - }); - - test('Should return relative path suggestions', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('a.md'), ''), - new InMemoryDocument(workspacePath('b.md'), ''), - new InMemoryDocument(workspacePath('sub/foo.md'), ''), - ]); - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[](${CURSOR}`, - ``, - `# A b C`, - ), workspace); - - assertCompletionsEqual(completions, [ - { label: '#a-b-c' }, - { label: 'a.md' }, - { label: 'b.md' }, - { label: 'sub/' }, - ]); - }); - - test('Should return relative path suggestions using ./', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('a.md'), ''), - new InMemoryDocument(workspacePath('b.md'), ''), - new InMemoryDocument(workspacePath('sub/foo.md'), ''), - ]); - - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[](./${CURSOR}`, - ``, - `# A b C`, - ), workspace); - - assertCompletionsEqual(completions, [ - { label: 'a.md' }, - { label: 'b.md' }, - { label: 'sub/' }, - ]); - }); - - test('Should return absolute path suggestions using /', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('a.md'), ''), - new InMemoryDocument(workspacePath('b.md'), ''), - new InMemoryDocument(workspacePath('sub/c.md'), ''), - ]); - - const completions = await getCompletionsAtCursor(workspacePath('sub', 'new.md'), joinLines( - `[](/${CURSOR}`, - ``, - `# A b C`, - ), workspace); - - assertCompletionsEqual(completions, [ - { label: 'a.md' }, - { label: 'b.md' }, - { label: 'sub/' }, - ]); - }); - - test('Should return anchor suggestions in other file', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('b.md'), joinLines( - `# b`, - ``, - `[./a](./a)`, - ``, - `# header1`, - )), - ]); - const completions = await getCompletionsAtCursor(workspacePath('sub', 'new.md'), joinLines( - `[](/b.md#${CURSOR}`, - ), workspace); - - assertCompletionsEqual(completions, [ - { label: '#b' }, - { label: '#header1' }, - ]); - }); - - test('Should reference links for current file', async () => { - const completions = await getCompletionsAtCursor(workspacePath('sub', 'new.md'), joinLines( - `[][${CURSOR}`, - ``, - `[ref-1]: bla`, - `[ref-2]: bla`, - )); - - assertCompletionsEqual(completions, [ - { label: 'ref-1' }, - { label: 'ref-2' }, - ]); - }); - - test('Should complete headers in link definitions', async () => { - const completions = await getCompletionsAtCursor(workspacePath('sub', 'new.md'), joinLines( - `# a B c`, - `# x y Z`, - `[ref-1]: ${CURSOR}`, - )); - - assertCompletionsEqual(completions, [ - { label: '#a-b-c' }, - { label: '#x-y-z' }, - { label: 'new.md' }, - ]); - }); - - test('Should complete relative paths in link definitions', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('a.md'), ''), - new InMemoryDocument(workspacePath('b.md'), ''), - new InMemoryDocument(workspacePath('sub/c.md'), ''), - ]); - - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `# a B c`, - `[ref-1]: ${CURSOR}`, - ), workspace); - - assertCompletionsEqual(completions, [ - { label: '#a-b-c' }, - { label: 'a.md' }, - { label: 'b.md' }, - { label: 'sub/' }, - ]); - }); - - test('Should escape spaces in path names', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('a.md'), ''), - new InMemoryDocument(workspacePath('b.md'), ''), - new InMemoryDocument(workspacePath('sub/file with space.md'), ''), - ]); - - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[](./sub/${CURSOR})` - ), workspace); - - assertCompletionsEqual(completions, [ - { label: 'file with space.md', insertText: 'file%20with%20space.md' }, - ]); - }); - - test('Should support completions on angle bracket path with spaces', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('sub with space/a.md'), ''), - new InMemoryDocument(workspacePath('b.md'), ''), - ]); - - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[]( { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('sub/file with space.md'), ''), - ]); - - { - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[](<./sub/${CURSOR}` - ), workspace); - - assertCompletionsEqual(completions, [ - { label: 'file with space.md', insertText: 'file with space.md' }, - ]); - } - { - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[](<./sub/${CURSOR}>` - ), workspace); - - assertCompletionsEqual(completions, [ - { label: 'file with space.md', insertText: 'file with space.md' }, - ]); - } - }); - - test('Should complete paths for path with encoded spaces', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('a.md'), ''), - new InMemoryDocument(workspacePath('b.md'), ''), - new InMemoryDocument(workspacePath('sub with space/file.md'), ''), - ]); - - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[](./sub%20with%20space/${CURSOR})` - ), workspace); - - assertCompletionsEqual(completions, [ - { label: 'file.md', insertText: 'file.md' }, - ]); - }); - - test('Should complete definition path for path with encoded spaces', async () => { - const workspace = new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('a.md'), ''), - new InMemoryDocument(workspacePath('b.md'), ''), - new InMemoryDocument(workspacePath('sub with space/file.md'), ''), - ]); - - const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( - `[def]: ./sub%20with%20space/${CURSOR}` - ), workspace); - - assertCompletionsEqual(completions, [ - { label: 'file.md', insertText: 'file.md' }, - ]); - }); -}); diff --git a/extensions/markdown-language-features/src/test/references.test.ts b/extensions/markdown-language-features/src/test/references.test.ts deleted file mode 100644 index 087ede35239..00000000000 --- a/extensions/markdown-language-features/src/test/references.test.ts +++ /dev/null @@ -1,635 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { MdReferencesProvider, MdVsCodeReferencesProvider } from '../languageFeatures/references'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { noopToken } from '../util/cancellation'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { IMdWorkspace } from '../workspace'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { joinLines, withStore, workspacePath } from './util'; - - -async function getReferences(store: DisposableStore, doc: InMemoryDocument, pos: vscode.Position, workspace: IMdWorkspace) { - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const computer = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); - const provider = new MdVsCodeReferencesProvider(computer); - const refs = await provider.provideReferences(doc, pos, { includeDeclaration: true }, noopToken); - return refs.sort((a, b) => { - const pathCompare = a.uri.toString().localeCompare(b.uri.toString()); - if (pathCompare !== 0) { - return pathCompare; - } - return a.range.start.compareTo(b.range.start); - }); -} - -function assertReferencesEqual(actualRefs: readonly vscode.Location[], ...expectedRefs: { uri: vscode.Uri; line: number; startCharacter?: number; endCharacter?: number }[]) { - assert.strictEqual(actualRefs.length, expectedRefs.length, `Reference counts should match`); - - for (let i = 0; i < actualRefs.length; ++i) { - const actual = actualRefs[i]; - const expected = expectedRefs[i]; - assert.strictEqual(actual.uri.toString(), expected.uri.toString(), `Ref '${i}' has expected document`); - assert.strictEqual(actual.range.start.line, expected.line, `Ref '${i}' has expected start line`); - assert.strictEqual(actual.range.end.line, expected.line, `Ref '${i}' has expected end line`); - if (typeof expected.startCharacter !== 'undefined') { - assert.strictEqual(actual.range.start.character, expected.startCharacter, `Ref '${i}' has expected start character`); - } - if (typeof expected.endCharacter !== 'undefined') { - assert.strictEqual(actual.range.end.character, expected.endCharacter, `Ref '${i}' has expected end character`); - } - } -} - -suite('Markdown: Find all references', () => { - test('Should not return references when not on header or link', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `# abc`, - ``, - `[link 1](#abc)`, - `text`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - { - const refs = await getReferences(store, doc, new vscode.Position(1, 0), workspace); - assert.deepStrictEqual(refs, []); - } - { - const refs = await getReferences(store, doc, new vscode.Position(3, 2), workspace); - assert.deepStrictEqual(refs, []); - } - })); - - test('Should find references from header within same file', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `# abc`, - ``, - `[link 1](#abc)`, - `[not link](#noabc)`, - `[link 2](#abc)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 3), workspace); - assertReferencesEqual(refs!, - { uri, line: 0 }, - { uri, line: 2 }, - { uri, line: 4 }, - ); - })); - - test('Should not return references when on link text', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `[ref](#abc)`, - `[ref]: http://example.com`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 1), workspace); - assert.deepStrictEqual(refs, []); - })); - - test('Should find references using normalized slug', withStore(async (store) => { - const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( - `# a B c`, - `[simple](#a-b-c)`, - `[start underscore](#_a-b-c)`, - `[different case](#a-B-C)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - { - // Trigger header - - const refs = await getReferences(store, doc, new vscode.Position(0, 0), workspace); - assert.deepStrictEqual(refs!.length, 4); - } - { - // Trigger on line 1 - const refs = await getReferences(store, doc, new vscode.Position(1, 12), workspace); - assert.deepStrictEqual(refs!.length, 4); - } - { - // Trigger on line 2 - const refs = await getReferences(store, doc, new vscode.Position(2, 24), workspace); - assert.deepStrictEqual(refs!.length, 4); - } - { - // Trigger on line 3 - const refs = await getReferences(store, doc, new vscode.Position(3, 20), workspace); - assert.deepStrictEqual(refs!.length, 4); - } - })); - - test('Should find references from header across files', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const other1Uri = workspacePath('sub', 'other.md'); - const other2Uri = workspacePath('zOther2.md'); - - const doc = new InMemoryDocument(docUri, joinLines( - `# abc`, - ``, - `[link 1](#abc)`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(other1Uri, joinLines( - `[not link](#abc)`, - `[not link](/doc.md#abz)`, - `[link](/doc.md#abc)` - )), - new InMemoryDocument(other2Uri, joinLines( - `[not link](#abc)`, - `[not link](./doc.md#abz)`, - `[link](./doc.md#abc)` - )) - ])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 3), workspace); - - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, // Header definition - { uri: docUri, line: 2 }, - { uri: other1Uri, line: 2 }, - { uri: other2Uri, line: 2 }, - ); - })); - - test('Should find references from header to link definitions ', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `# abc`, - ``, - `[bla]: #abc` - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 3), workspace); - assertReferencesEqual(refs!, - { uri, line: 0 }, // Header definition - { uri, line: 2 }, - ); - })); - - test('Should find header references from link definition', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `# A b C`, - `[text][bla]`, - `[bla]: #a-b-c`, // trigger here - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(2, 9), workspace); - assertReferencesEqual(refs!, - { uri, line: 0 }, // Header definition - { uri, line: 2 }, - ); - })); - - test('Should find references from link within same file', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `# abc`, - ``, - `[link 1](#abc)`, - `[not link](#noabc)`, - `[link 2](#abc)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(2, 10), workspace); - assertReferencesEqual(refs!, - { uri, line: 0 }, // Header definition - { uri, line: 2 }, - { uri, line: 4 }, - ); - })); - - test('Should find references from link across files', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const other1Uri = workspacePath('sub', 'other.md'); - const other2Uri = workspacePath('zOther2.md'); - - const doc = new InMemoryDocument(docUri, joinLines( - `# abc`, - ``, - `[link 1](#abc)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(other1Uri, joinLines( - `[not link](#abc)`, - `[not link](/doc.md#abz)`, - `[with ext](/doc.md#abc)`, - `[without ext](/doc#abc)` - )), - new InMemoryDocument(other2Uri, joinLines( - `[not link](#abc)`, - `[not link](./doc.md#abz)`, - `[link](./doc.md#abc)` - )) - ])); - - const refs = await getReferences(store, doc, new vscode.Position(2, 10), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, // Header definition - { uri: docUri, line: 2 }, - { uri: other1Uri, line: 2 }, // Other with ext - { uri: other1Uri, line: 3 }, // Other without ext - { uri: other2Uri, line: 2 }, // Other2 - ); - })); - - test('Should find references without requiring file extensions', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const other1Uri = workspacePath('other.md'); - - const doc = new InMemoryDocument(docUri, joinLines( - `# a B c`, - ``, - `[link 1](#a-b-c)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(other1Uri, joinLines( - `[not link](#a-b-c)`, - `[not link](/doc.md#a-b-z)`, - `[with ext](/doc.md#a-b-c)`, - `[without ext](/doc#a-b-c)`, - `[rel with ext](./doc.md#a-b-c)`, - `[rel without ext](./doc#a-b-c)` - )), - ])); - - const refs = await getReferences(store, doc, new vscode.Position(2, 10), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, // Header definition - { uri: docUri, line: 2 }, - { uri: other1Uri, line: 2 }, // Other with ext - { uri: other1Uri, line: 3 }, // Other without ext - { uri: other1Uri, line: 4 }, // Other relative link with ext - { uri: other1Uri, line: 5 }, // Other relative link without ext - ); - })); - - test('Should find references from link across files when triggered on link without file extension', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const other1Uri = workspacePath('sub', 'other.md'); - - const doc = new InMemoryDocument(docUri, joinLines( - `[with ext](./sub/other#header)`, - `[without ext](./sub/other.md#header)`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(other1Uri, joinLines( - `pre`, - `# header`, - `post` - )), - ])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 23), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - { uri: docUri, line: 1 }, - { uri: other1Uri, line: 1 }, // Header definition - ); - })); - - test('Should include header references when triggered on file link', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const otherUri = workspacePath('sub', 'other.md'); - - const doc = new InMemoryDocument(docUri, joinLines( - `[with ext](./sub/other)`, - `[with ext](./sub/other#header)`, - `[without ext](./sub/other.md#no-such-header)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(otherUri, joinLines( - `pre`, - `# header`, - `post` - )), - ])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 15), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - { uri: docUri, line: 1 }, - { uri: docUri, line: 2 }, - ); - })); - - test('Should not include refs from other file to own header', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const otherUri = workspacePath('sub', 'other.md'); - - const doc = new InMemoryDocument(docUri, joinLines( - `[other](./sub/other)`, // trigger here - )); - - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(otherUri, joinLines( - `# header`, // Definition should not be included since we triggered on a file link - `[text](#header)`, // Ref should not be included since it is to own file - )), - ])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 15), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - ); - })); - - test('Should find explicit references to own file ', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[bare](doc.md)`, // trigger here - `[rel](./doc.md)`, - `[abs](/doc.md)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 12), workspace); - assertReferencesEqual(refs!, - { uri, line: 0 }, - { uri, line: 1 }, - { uri, line: 2 }, - ); - })); - - test('Should support finding references to http uri', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[1](http://example.com)`, - `[no](https://example.com)`, - `[2](http://example.com)`, - `[3]: http://example.com`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 13), workspace); - assertReferencesEqual(refs!, - { uri, line: 0 }, - { uri, line: 2 }, - { uri, line: 3 }, - ); - })); - - test('Should consider authority, scheme and paths when finding references to http uri', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[1](http://example.com/cat)`, - `[2](http://example.com)`, - `[3](http://example.com/dog)`, - `[4](http://example.com/cat/looong)`, - `[5](http://example.com/cat)`, - `[6](http://other.com/cat)`, - `[7](https://example.com/cat)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 13), workspace); - assertReferencesEqual(refs!, - { uri, line: 0 }, - { uri, line: 4 }, - ); - })); - - test('Should support finding references to http uri across files', withStore(async (store) => { - const uri1 = workspacePath('doc.md'); - const uri2 = workspacePath('doc2.md'); - const doc = new InMemoryDocument(uri1, joinLines( - `[1](http://example.com)`, - `[3]: http://example.com`, - )); - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(uri2, joinLines( - `[other](http://example.com)` - )) - ])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 13), workspace); - assertReferencesEqual(refs!, - { uri: uri1, line: 0 }, - { uri: uri1, line: 1 }, - { uri: uri2, line: 0 }, - ); - })); - - test('Should support finding references to autolinked http links', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[1](http://example.com)`, - ``, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 13), workspace); - assertReferencesEqual(refs!, - { uri, line: 0 }, - { uri, line: 1 }, - ); - })); - - test('Should distinguish between references to file and to header within file', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const other1Uri = workspacePath('sub', 'other.md'); - - const doc = new InMemoryDocument(docUri, joinLines( - `# abc`, - ``, - `[link 1](#abc)`, - )); - const otherDoc = new InMemoryDocument(other1Uri, joinLines( - `[link](/doc.md#abc)`, - `[link no text](/doc#abc)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - otherDoc, - ])); - - { - // Check refs to header fragment - const headerRefs = await getReferences(store, otherDoc, new vscode.Position(0, 16), workspace); - assertReferencesEqual(headerRefs, - { uri: docUri, line: 0 }, // Header definition - { uri: docUri, line: 2 }, - { uri: other1Uri, line: 0 }, - { uri: other1Uri, line: 1 }, - ); - } - { - // Check refs to file itself from link with ext - const fileRefs = await getReferences(store, otherDoc, new vscode.Position(0, 9), workspace); - assertReferencesEqual(fileRefs, - { uri: other1Uri, line: 0, endCharacter: 14 }, - { uri: other1Uri, line: 1, endCharacter: 19 }, - ); - } - { - // Check refs to file itself from link without ext - const fileRefs = await getReferences(store, otherDoc, new vscode.Position(1, 17), workspace); - assertReferencesEqual(fileRefs, - { uri: other1Uri, line: 0 }, - { uri: other1Uri, line: 1 }, - ); - } - })); - - test('Should support finding references to unknown file', withStore(async (store) => { - const uri1 = workspacePath('doc1.md'); - const doc1 = new InMemoryDocument(uri1, joinLines( - `![img](/images/more/image.png)`, - ``, - `[ref]: /images/more/image.png`, - )); - - const uri2 = workspacePath('sub', 'doc2.md'); - const doc2 = new InMemoryDocument(uri2, joinLines( - `![img](/images/more/image.png)`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc1, doc2])); - - const refs = await getReferences(store, doc1, new vscode.Position(0, 10), workspace); - assertReferencesEqual(refs!, - { uri: uri1, line: 0 }, - { uri: uri1, line: 2 }, - { uri: uri2, line: 0 }, - ); - })); - - suite('Reference links', () => { - test('Should find reference links within file from link', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `[link 1][abc]`, // trigger here - ``, - `[abc]: https://example.com`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 12), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - { uri: docUri, line: 2 }, - ); - })); - - test('Should find reference links using shorthand', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `[ref]`, // trigger 1 - ``, - `[yes][ref]`, // trigger 2 - ``, - `[ref]: /Hello.md` // trigger 3 - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - { - const refs = await getReferences(store, doc, new vscode.Position(0, 2), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - { uri: docUri, line: 2 }, - { uri: docUri, line: 4 }, - ); - } - { - const refs = await getReferences(store, doc, new vscode.Position(2, 7), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - { uri: docUri, line: 2 }, - { uri: docUri, line: 4 }, - ); - } - { - const refs = await getReferences(store, doc, new vscode.Position(4, 2), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - { uri: docUri, line: 2 }, - { uri: docUri, line: 4 }, - ); - } - })); - - test('Should find reference links within file from definition', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `[link 1][abc]`, - ``, - `[abc]: https://example.com`, // trigger here - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(2, 3), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - { uri: docUri, line: 2 }, - ); - })); - - test('Should not find reference links across files', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `[link 1][abc]`, - ``, - `[abc]: https://example.com`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(workspacePath('other.md'), joinLines( - `[link 1][abc]`, - ``, - `[abc]: https://example.com?bad` - )) - ])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 12), workspace); - assertReferencesEqual(refs!, - { uri: docUri, line: 0 }, - { uri: docUri, line: 2 }, - ); - })); - - test('Should not consider checkboxes as reference links', withStore(async (store) => { - const docUri = workspacePath('doc.md'); - const doc = new InMemoryDocument(docUri, joinLines( - `- [x]`, - `- [X]`, - `- [ ]`, - ``, - `[x]: https://example.com` - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const refs = await getReferences(store, doc, new vscode.Position(0, 4), workspace); - assert.strictEqual(refs?.length!, 0); - })); - }); -}); diff --git a/extensions/markdown-language-features/src/test/rename.test.ts b/extensions/markdown-language-features/src/test/rename.test.ts deleted file mode 100644 index 48e8d990321..00000000000 --- a/extensions/markdown-language-features/src/test/rename.test.ts +++ /dev/null @@ -1,720 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { MdReferencesProvider } from '../languageFeatures/references'; -import { MdVsCodeRenameProvider, MdWorkspaceEdit } from '../languageFeatures/rename'; -import { githubSlugifier } from '../slugify'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { noopToken } from '../util/cancellation'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { IMdWorkspace } from '../workspace'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { assertRangeEqual, joinLines, withStore, workspacePath } from './util'; - - -/** - * Get prepare rename info. - */ -function prepareRename(store: DisposableStore, doc: InMemoryDocument, pos: vscode.Position, workspace: IMdWorkspace): Promise { - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const referenceComputer = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); - const renameProvider = store.add(new MdVsCodeRenameProvider(workspace, referenceComputer, githubSlugifier)); - return renameProvider.prepareRename(doc, pos, noopToken); -} - -/** - * Get all the edits for the rename. - */ -function getRenameEdits(store: DisposableStore, doc: InMemoryDocument, pos: vscode.Position, newName: string, workspace: IMdWorkspace): Promise { - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const referencesProvider = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); - const renameProvider = store.add(new MdVsCodeRenameProvider(workspace, referencesProvider, githubSlugifier)); - return renameProvider.provideRenameEditsImpl(doc, pos, newName, noopToken); -} - -interface ExpectedTextEdit { - readonly uri: vscode.Uri; - readonly edits: readonly vscode.TextEdit[]; -} - -interface ExpectedFileRename { - readonly originalUri: vscode.Uri; - readonly newUri: vscode.Uri; -} - -function assertEditsEqual(actualEdit: MdWorkspaceEdit, ...expectedEdits: ReadonlyArray) { - // Check file renames - const expectedFileRenames = expectedEdits.filter(expected => 'originalUri' in expected) as ExpectedFileRename[]; - const actualFileRenames = actualEdit.fileRenames ?? []; - assert.strictEqual(actualFileRenames.length, expectedFileRenames.length, `File rename count should match`); - for (let i = 0; i < actualFileRenames.length; ++i) { - const expected = expectedFileRenames[i]; - const actual = actualFileRenames[i]; - assert.strictEqual(actual.from.toString(), expected.originalUri.toString(), `File rename '${i}' should have expected 'from' resource`); - assert.strictEqual(actual.to.toString(), expected.newUri.toString(), `File rename '${i}' should have expected 'to' resource`); - } - - // Check text edits - const actualTextEdits = actualEdit.edit.entries(); - const expectedTextEdits = expectedEdits.filter(expected => 'edits' in expected) as ExpectedTextEdit[]; - assert.strictEqual(actualTextEdits.length, expectedTextEdits.length, `Reference counts should match`); - for (let i = 0; i < actualTextEdits.length; ++i) { - const expected = expectedTextEdits[i]; - const actual = actualTextEdits[i]; - - if ('edits' in expected) { - assert.strictEqual(actual[0].toString(), expected.uri.toString(), `Ref '${i}' has expected document`); - - const actualEditForDoc = actual[1]; - const expectedEditsForDoc = expected.edits; - assert.strictEqual(actualEditForDoc.length, expectedEditsForDoc.length, `Edit counts for '${actual[0]}' should match`); - - for (let g = 0; g < actualEditForDoc.length; ++g) { - assertRangeEqual(actualEditForDoc[g].range, expectedEditsForDoc[g].range, `Edit '${g}' of '${actual[0]}' has expected expected range. Expected range: ${JSON.stringify(actualEditForDoc[g].range)}. Actual range: ${JSON.stringify(expectedEditsForDoc[g].range)}`); - assert.strictEqual(actualEditForDoc[g].newText, expectedEditsForDoc[g].newText, `Edit '${g}' of '${actual[0]}' has expected edits`); - } - } - } -} - -suite('markdown: rename', () => { - - setup(async () => { - // the tests make the assumption that link providers are already registered - await vscode.extensions.getExtension('vscode.markdown-language-features')!.activate(); - }); - - test('Rename on header should not include leading #', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `# abc` - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const info = await prepareRename(store, doc, new vscode.Position(0, 0), workspace); - assertRangeEqual(info!.range, new vscode.Range(0, 2, 0, 5)); - - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 0), "New Header", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 2, 0, 5), 'New Header') - ] - }); - })); - - test('Rename on header should include leading or trailing #s', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `### abc ###` - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const info = await prepareRename(store, doc, new vscode.Position(0, 0), workspace); - assertRangeEqual(info!.range, new vscode.Range(0, 4, 0, 7)); - - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 0), "New Header", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 7), 'New Header') - ] - }); - })); - - test('Rename on header should pick up links in doc', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `### A b C`, // rename here - `[text](#a-b-c)`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 0), "New Header", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 9), 'New Header'), - new vscode.TextEdit(new vscode.Range(1, 8, 1, 13), 'new-header'), - ] - }); - })); - - test('Rename on link should use slug for link', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `### A b C`, - `[text](#a-b-c)`, // rename here - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const edit = await getRenameEdits(store, doc, new vscode.Position(1, 10), "New Header", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 9), 'New Header'), - new vscode.TextEdit(new vscode.Range(1, 8, 1, 13), 'new-header'), - ] - }); - })); - - test('Rename on link definition should work', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `### A b C`, - `[text](#a-b-c)`, - `[ref]: #a-b-c`// rename here - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const edit = await getRenameEdits(store, doc, new vscode.Position(2, 10), "New Header", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 9), 'New Header'), - new vscode.TextEdit(new vscode.Range(1, 8, 1, 13), 'new-header'), - new vscode.TextEdit(new vscode.Range(2, 8, 2, 13), 'new-header'), - ] - }); - })); - - test('Rename on header should pick up links across files', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const otherUri = workspacePath('other.md'); - const doc = new InMemoryDocument(uri, joinLines( - `### A b C`, // rename here - `[text](#a-b-c)`, - )); - - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 0), "New Header", new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(otherUri, joinLines( - `[text](#a-b-c)`, // Should not find this - `[text](./doc.md#a-b-c)`, // But should find this - `[text](./doc#a-b-c)`, // And this - )) - ])); - assertEditsEqual(edit!, { - uri: uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 9), 'New Header'), - new vscode.TextEdit(new vscode.Range(1, 8, 1, 13), 'new-header'), - ] - }, { - uri: otherUri, edits: [ - new vscode.TextEdit(new vscode.Range(1, 16, 1, 21), 'new-header'), - new vscode.TextEdit(new vscode.Range(2, 13, 2, 18), 'new-header'), - ] - }); - })); - - test('Rename on link should pick up links across files', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const otherUri = workspacePath('other.md'); - const doc = new InMemoryDocument(uri, joinLines( - `### A b C`, - `[text](#a-b-c)`, // rename here - )); - - const edit = await getRenameEdits(store, doc, new vscode.Position(1, 10), "New Header", new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(otherUri, joinLines( - `[text](#a-b-c)`, // Should not find this - `[text](./doc.md#a-b-c)`, // But should find this - `[text](./doc#a-b-c)`, // And this - )) - ])); - assertEditsEqual(edit!, { - uri: uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 9), 'New Header'), - new vscode.TextEdit(new vscode.Range(1, 8, 1, 13), 'new-header'), - ] - }, { - uri: otherUri, edits: [ - new vscode.TextEdit(new vscode.Range(1, 16, 1, 21), 'new-header'), - new vscode.TextEdit(new vscode.Range(2, 13, 2, 18), 'new-header'), - ] - }); - })); - - test('Rename on link in other file should pick up all refs', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const otherUri = workspacePath('other.md'); - const doc = new InMemoryDocument(uri, joinLines( - `### A b C`, - `[text](#a-b-c)`, - )); - - const otherDoc = new InMemoryDocument(otherUri, joinLines( - `[text](#a-b-c)`, - `[text](./doc.md#a-b-c)`, - `[text](./doc#a-b-c)` - )); - - const expectedEdits = [ - { - uri: uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 9), 'New Header'), - new vscode.TextEdit(new vscode.Range(1, 8, 1, 13), 'new-header'), - ] - }, { - uri: otherUri, edits: [ - new vscode.TextEdit(new vscode.Range(1, 16, 1, 21), 'new-header'), - new vscode.TextEdit(new vscode.Range(2, 13, 2, 18), 'new-header'), - ] - } - ]; - - { - // Rename on header with file extension - const edit = await getRenameEdits(store, otherDoc, new vscode.Position(1, 17), "New Header", new InMemoryMdWorkspace([ - doc, - otherDoc - ])); - assertEditsEqual(edit!, ...expectedEdits); - } - { - // Rename on header without extension - const edit = await getRenameEdits(store, otherDoc, new vscode.Position(2, 15), "New Header", new InMemoryMdWorkspace([ - doc, - otherDoc - ])); - assertEditsEqual(edit!, ...expectedEdits); - } - })); - - test('Rename on reference should rename references and definition', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text][ref]`, // rename here - `[other][ref]`, - ``, - `[ref]: https://example.com`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 8), "new ref", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 10), 'new ref'), - new vscode.TextEdit(new vscode.Range(1, 8, 1, 11), 'new ref'), - new vscode.TextEdit(new vscode.Range(3, 1, 3, 4), 'new ref'), - ] - }); - })); - - test('Rename on definition should rename references and definitions', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text][ref]`, - `[other][ref]`, - ``, - `[ref]: https://example.com`, // rename here - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const edit = await getRenameEdits(store, doc, new vscode.Position(3, 3), "new ref", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 10), 'new ref'), - new vscode.TextEdit(new vscode.Range(1, 8, 1, 11), 'new ref'), - new vscode.TextEdit(new vscode.Range(3, 1, 3, 4), 'new ref'), - ] - }); - })); - - test('Rename on definition entry should rename header and references', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `# a B c`, - `[ref text][ref]`, - `[direct](#a-b-c)`, - `[ref]: #a-b-c`, // rename here - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const preparedInfo = await prepareRename(store, doc, new vscode.Position(3, 10), workspace); - assert.strictEqual(preparedInfo!.placeholder, 'a B c'); - assertRangeEqual(preparedInfo!.range, new vscode.Range(3, 8, 3, 13)); - - const edit = await getRenameEdits(store, doc, new vscode.Position(3, 10), "x Y z", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 2, 0, 7), 'x Y z'), - new vscode.TextEdit(new vscode.Range(2, 10, 2, 15), 'x-y-z'), - new vscode.TextEdit(new vscode.Range(3, 8, 3, 13), 'x-y-z'), - ] - }); - })); - - test('Rename should not be supported on link text', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `# Header`, - `[text](#header)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - await assert.rejects(prepareRename(store, doc, new vscode.Position(1, 2), workspace)); - })); - - test('Path rename should use file path as range', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text](./doc.md)`, - `[ref]: ./doc.md`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const info = await prepareRename(store, doc, new vscode.Position(0, 10), workspace); - assert.strictEqual(info!.placeholder, './doc.md'); - assertRangeEqual(info!.range, new vscode.Range(0, 7, 0, 15)); - })); - - test('Path rename\'s range should excludes fragment', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text](./doc.md#some-header)`, - `[ref]: ./doc.md#some-header`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const info = await prepareRename(store, doc, new vscode.Position(0, 10), workspace); - assert.strictEqual(info!.placeholder, './doc.md'); - assertRangeEqual(info!.range, new vscode.Range(0, 7, 0, 15)); - })); - - test('Path rename should update file and all refs', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text](./doc.md)`, - `[ref]: ./doc.md`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 10), './sub/newDoc.md', workspace); - assertEditsEqual(edit!, { - originalUri: uri, - newUri: workspacePath('sub', 'newDoc.md'), - }, { - uri: uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 15), './sub/newDoc.md'), - new vscode.TextEdit(new vscode.Range(1, 7, 1, 15), './sub/newDoc.md'), - ] - }); - })); - - test('Path rename using absolute file path should anchor to workspace root', withStore(async (store) => { - const uri = workspacePath('sub', 'doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text](/sub/doc.md)`, - `[ref]: /sub/doc.md`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 10), '/newSub/newDoc.md', workspace); - assertEditsEqual(edit!, { - originalUri: uri, - newUri: workspacePath('newSub', 'newDoc.md'), - }, { - uri: uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 18), '/newSub/newDoc.md'), - new vscode.TextEdit(new vscode.Range(1, 7, 1, 18), '/newSub/newDoc.md'), - ] - }); - })); - - test('Path rename should use un-encoded paths as placeholder', withStore(async (store) => { - const uri = workspacePath('sub', 'doc with spaces.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text](/sub/doc%20with%20spaces.md)`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const info = await prepareRename(store, doc, new vscode.Position(0, 10), workspace); - assert.strictEqual(info!.placeholder, '/sub/doc with spaces.md'); - })); - - test('Path rename should encode paths', withStore(async (store) => { - const uri = workspacePath('sub', 'doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text](/sub/doc.md)`, - `[ref]: /sub/doc.md`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 10), '/NEW sub/new DOC.md', workspace); - assertEditsEqual(edit!, { - originalUri: uri, - newUri: workspacePath('NEW sub', 'new DOC.md'), - }, { - uri: uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 18), '/NEW%20sub/new%20DOC.md'), - new vscode.TextEdit(new vscode.Range(1, 7, 1, 18), '/NEW%20sub/new%20DOC.md'), - ] - }); - })); - - test('Path rename should work with unknown files', withStore(async (store) => { - const uri1 = workspacePath('doc1.md'); - const doc1 = new InMemoryDocument(uri1, joinLines( - `![img](/images/more/image.png)`, - ``, - `[ref]: /images/more/image.png`, - )); - - const uri2 = workspacePath('sub', 'doc2.md'); - const doc2 = new InMemoryDocument(uri2, joinLines( - `![img](/images/more/image.png)`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([ - doc1, - doc2 - ])); - - const edit = await getRenameEdits(store, doc1, new vscode.Position(0, 10), '/img/test/new.png', workspace); - assertEditsEqual(edit!, - // Should not have file edits since the files don't exist here - { - uri: uri1, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 29), '/img/test/new.png'), - new vscode.TextEdit(new vscode.Range(2, 7, 2, 29), '/img/test/new.png'), - ] - }, - { - uri: uri2, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 29), '/img/test/new.png'), - ] - }); - })); - - test('Path rename should use .md extension on extension-less link', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[text](/doc#header)`, - `[ref]: /doc#other`, - )); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const edit = await getRenameEdits(store, doc, new vscode.Position(0, 10), '/new File', workspace); - assertEditsEqual(edit!, { - originalUri: uri, - newUri: workspacePath('new File.md'), // Rename on disk should use file extension - }, { - uri: uri, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 11), '/new%20File'), // Links should continue to use extension-less paths - new vscode.TextEdit(new vscode.Range(1, 7, 1, 11), '/new%20File'), - ] - }); - })); - - // TODO: fails on windows - test.skip('Path rename should use correctly resolved paths across files', withStore(async (store) => { - const uri1 = workspacePath('sub', 'doc.md'); - const doc1 = new InMemoryDocument(uri1, joinLines( - `[text](./doc.md)`, - `[ref]: ./doc.md`, - )); - - const uri2 = workspacePath('doc2.md'); - const doc2 = new InMemoryDocument(uri2, joinLines( - `[text](./sub/doc.md)`, - `[ref]: ./sub/doc.md`, - )); - - const uri3 = workspacePath('sub2', 'doc3.md'); - const doc3 = new InMemoryDocument(uri3, joinLines( - `[text](../sub/doc.md)`, - `[ref]: ../sub/doc.md`, - )); - - const uri4 = workspacePath('sub2', 'doc4.md'); - const doc4 = new InMemoryDocument(uri4, joinLines( - `[text](/sub/doc.md)`, - `[ref]: /sub/doc.md`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([ - doc1, doc2, doc3, doc4, - ])); - - const edit = await getRenameEdits(store, doc1, new vscode.Position(0, 10), './new/new-doc.md', workspace); - assertEditsEqual(edit!, { - originalUri: uri1, - newUri: workspacePath('sub', 'new', 'new-doc.md'), - }, { - uri: uri1, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 15), './new/new-doc.md'), - new vscode.TextEdit(new vscode.Range(1, 7, 1, 15), './new/new-doc.md'), - ] - }, { - uri: uri2, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 19), './sub/new/new-doc.md'), - new vscode.TextEdit(new vscode.Range(1, 7, 1, 19), './sub/new/new-doc.md'), - ] - }, { - uri: uri3, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 20), '../sub/new/new-doc.md'), - new vscode.TextEdit(new vscode.Range(1, 7, 1, 20), '../sub/new/new-doc.md'), - ] - }, { - uri: uri4, edits: [ - new vscode.TextEdit(new vscode.Range(0, 7, 0, 18), '/sub/new/new-doc.md'), - new vscode.TextEdit(new vscode.Range(1, 7, 1, 18), '/sub/new/new-doc.md'), - ] - }); - })); - - test('Path rename should resolve on links without prefix', withStore(async (store) => { - const uri1 = workspacePath('sub', 'doc.md'); - const doc1 = new InMemoryDocument(uri1, joinLines( - `![text](sub2/doc3.md)`, - )); - - const uri2 = workspacePath('doc2.md'); - const doc2 = new InMemoryDocument(uri2, joinLines( - `![text](sub/sub2/doc3.md)`, - )); - - const uri3 = workspacePath('sub', 'sub2', 'doc3.md'); - const doc3 = new InMemoryDocument(uri3, joinLines()); - - const workspace = store.add(new InMemoryMdWorkspace([ - doc1, doc2, doc3 - ])); - - const edit = await getRenameEdits(store, doc1, new vscode.Position(0, 10), 'sub2/cat.md', workspace); - assertEditsEqual(edit!, { - originalUri: workspacePath('sub', 'sub2', 'doc3.md'), - newUri: workspacePath('sub', 'sub2', 'cat.md'), - }, { - uri: uri1, edits: [new vscode.TextEdit(new vscode.Range(0, 8, 0, 20), 'sub2/cat.md')] - }, { - uri: uri2, edits: [new vscode.TextEdit(new vscode.Range(0, 8, 0, 24), 'sub/sub2/cat.md')] - }); - })); - - test('Rename on link should use header text as placeholder', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `### a B c ###`, - `[text](#a-b-c)`, - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const info = await prepareRename(store, doc, new vscode.Position(1, 10), workspace); - assert.strictEqual(info!.placeholder, 'a B c'); - assertRangeEqual(info!.range, new vscode.Range(1, 8, 1, 13)); - })); - - test('Rename on http uri should work', withStore(async (store) => { - const uri1 = workspacePath('doc.md'); - const uri2 = workspacePath('doc2.md'); - const doc = new InMemoryDocument(uri1, joinLines( - `[1](http://example.com)`, - `[2]: http://example.com`, - ``, - )); - - const workspace = store.add(new InMemoryMdWorkspace([ - doc, - new InMemoryDocument(uri2, joinLines( - `[4](http://example.com)` - )) - ])); - - const edit = await getRenameEdits(store, doc, new vscode.Position(1, 10), "https://example.com/sub", workspace); - assertEditsEqual(edit!, { - uri: uri1, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 22), 'https://example.com/sub'), - new vscode.TextEdit(new vscode.Range(1, 5, 1, 23), 'https://example.com/sub'), - new vscode.TextEdit(new vscode.Range(2, 1, 2, 19), 'https://example.com/sub'), - ] - }, { - uri: uri2, edits: [ - new vscode.TextEdit(new vscode.Range(0, 4, 0, 22), 'https://example.com/sub'), - ] - }); - })); - - test('Rename on definition path should update all references to path', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[ref text][ref]`, - `[direct](/file)`, - `[ref]: /file`, // rename here - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const preparedInfo = await prepareRename(store, doc, new vscode.Position(2, 10), workspace); - assert.strictEqual(preparedInfo!.placeholder, '/file'); - assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 7, 2, 12)); - - const edit = await getRenameEdits(store, doc, new vscode.Position(2, 10), "/newFile", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(1, 9, 1, 14), '/newFile'), - new vscode.TextEdit(new vscode.Range(2, 7, 2, 12), '/newFile'), - ] - }); - })); - - test('Rename on definition path where file exists should also update file', withStore(async (store) => { - const uri1 = workspacePath('doc.md'); - const doc1 = new InMemoryDocument(uri1, joinLines( - `[ref text][ref]`, - `[direct](/doc2)`, - `[ref]: /doc2`, // rename here - )); - - const uri2 = workspacePath('doc2.md'); - const doc2 = new InMemoryDocument(uri2, joinLines()); - - const workspace = store.add(new InMemoryMdWorkspace([doc1, doc2])); - - const preparedInfo = await prepareRename(store, doc1, new vscode.Position(2, 10), workspace); - assert.strictEqual(preparedInfo!.placeholder, '/doc2'); - assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 7, 2, 12)); - - const edit = await getRenameEdits(store, doc1, new vscode.Position(2, 10), "/new-doc", workspace); - assertEditsEqual(edit!, { - uri: uri1, edits: [ - new vscode.TextEdit(new vscode.Range(1, 9, 1, 14), '/new-doc'), - new vscode.TextEdit(new vscode.Range(2, 7, 2, 12), '/new-doc'), - ] - }, { - originalUri: uri2, - newUri: workspacePath('new-doc.md') - }); - })); - - test('Rename on definition path header should update all references to header', withStore(async (store) => { - const uri = workspacePath('doc.md'); - const doc = new InMemoryDocument(uri, joinLines( - `[ref text][ref]`, - `[direct](/file#header)`, - `[ref]: /file#header`, // rename here - )); - - const workspace = store.add(new InMemoryMdWorkspace([doc])); - - const preparedInfo = await prepareRename(store, doc, new vscode.Position(2, 16), workspace); - assert.strictEqual(preparedInfo!.placeholder, 'header'); - assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 13, 2, 19)); - - const edit = await getRenameEdits(store, doc, new vscode.Position(2, 16), "New Header", workspace); - assertEditsEqual(edit!, { - uri, edits: [ - new vscode.TextEdit(new vscode.Range(1, 15, 1, 21), 'new-header'), - new vscode.TextEdit(new vscode.Range(2, 13, 2, 19), 'new-header'), - ] - }); - })); -}); diff --git a/extensions/markdown-language-features/src/test/smartSelect.test.ts b/extensions/markdown-language-features/src/test/smartSelect.test.ts deleted file mode 100644 index eb0be03af34..00000000000 --- a/extensions/markdown-language-features/src/test/smartSelect.test.ts +++ /dev/null @@ -1,731 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import * as vscode from 'vscode'; -import { MdSmartSelect } from '../languageFeatures/smartSelect'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { CURSOR, getCursorPositions, joinLines } from './util'; - -const testFileName = vscode.Uri.file('test.md'); - -suite('markdown.SmartSelect', () => { - test('Smart select single word', async () => { - const ranges = await getSelectionRangesForDocument(`Hel${CURSOR}lo`); - assertNestedLineNumbersEqual(ranges![0], [0, 0]); - }); - - test('Smart select multi-line paragraph', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `Many of the core components and extensions to ${CURSOR}VS Code live in their own repositories on GitHub. `, - `For example, the[node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter]`, - `(https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/microsoft/vscode/wiki).` - )); - assertNestedLineNumbersEqual(ranges![0], [0, 2]); - }); - - test('Smart select paragraph', async () => { - const ranges = await getSelectionRangesForDocument(`Many of the core components and extensions to ${CURSOR}VS Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/microsoft/vscode/wiki).`); - - assertNestedLineNumbersEqual(ranges![0], [0, 0]); - }); - - test('Smart select html block', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `

`, - `${CURSOR}VS Code in action`, - `

`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 2]); - }); - - test('Smart select header on header line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# Header${CURSOR}`, - `Hello`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 1]); - - }); - - test('Smart select single word w grandparent header on text line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `## ParentHeader`, - `# Header`, - `${CURSOR}Hello` - )); - - assertNestedLineNumbersEqual(ranges![0], [2, 2], [1, 2]); - }); - - test('Smart select html block w parent header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# Header`, - `${CURSOR}

`, - `VS Code in action`, - `

`)); - - assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 3], [0, 3]); - }); - - test('Smart select fenced code block', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `~~~`, - `a${CURSOR}`, - `~~~`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 2]); - }); - - test('Smart select list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `- item 1`, - `- ${CURSOR}item 2`, - `- item 3`, - `- item 4`)); - assertNestedLineNumbersEqual(ranges![0], [1, 1], [0, 3]); - }); - - test('Smart select list with fenced code block', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `- item 1`, - `- ~~~`, - ` ${CURSOR}a`, - ` ~~~`, - `- item 3`, - `- item 4`)); - - assertNestedLineNumbersEqual(ranges![0], [1, 3], [0, 5]); - }); - - test('Smart select multi cursor', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `- ${CURSOR}item 1`, - `- ~~~`, - ` a`, - ` ~~~`, - `- ${CURSOR}item 3`, - `- item 4`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 0], [0, 5]); - assertNestedLineNumbersEqual(ranges![1], [4, 4], [0, 5]); - }); - - test('Smart select nested block quotes', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `> item 1`, - `> item 2`, - `>> ${CURSOR}item 3`, - `>> item 4`)); - assertNestedLineNumbersEqual(ranges![0], [2, 2], [2, 3], [0, 3]); - }); - - test('Smart select multi nested block quotes', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `> item 1`, - `>> item 2`, - `>>> ${CURSOR}item 3`, - `>>>> item 4`)); - assertNestedLineNumbersEqual(ranges![0], [2, 2], [2, 3], [1, 3], [0, 3]); - }); - - test('Smart select subheader content', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - `content 1`, - `## sub header 1`, - `${CURSOR}content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [3, 3], [2, 3], [1, 3], [0, 3]); - }); - - test('Smart select subheader line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - `content 1`, - `## sub header 1${CURSOR}`, - `content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [2, 3], [1, 3], [0, 3]); - }); - - test('Smart select blank line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - `content 1`, - `${CURSOR} `, - `content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [1, 3], [0, 3]); - }); - - test('Smart select line between paragraphs', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `paragraph 1`, - `${CURSOR}`, - `paragraph 2`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 2]); - }); - - test('Smart select empty document', async () => { - const ranges = await getSelectionRangesForDocument(``, [new vscode.Position(0, 0)]); - assert.strictEqual(ranges!.length, 0); - }); - - test('Smart select fenced code block then list then subheader content then subheader then header content then header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - /* 00 */ `# main header 1`, - /* 01 */ `content 1`, - /* 02 */ `## sub header 1`, - /* 03 */ `- item 1`, - /* 04 */ `- ~~~`, - /* 05 */ ` ${CURSOR}a`, - /* 06 */ ` ~~~`, - /* 07 */ `- item 3`, - /* 08 */ `- item 4`, - /* 09 */ ``, - /* 10 */ `more content`, - /* 11 */ `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [4, 6], [3, 8], [3, 10], [2, 10], [1, 10], [0, 10]); - }); - - test('Smart select list with one element without selecting child subheader', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - /* 00 */ `# main header 1`, - /* 01 */ ``, - /* 02 */ `- list ${CURSOR}`, - /* 03 */ ``, - /* 04 */ `## sub header`, - /* 05 */ ``, - /* 06 */ `content 2`, - /* 07 */ `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [2, 2], [1, 3], [1, 6], [0, 6]); - }); - - test('Smart select content under header then subheaders and their content', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main ${CURSOR}header 1`, - ``, - `- list`, - `paragraph`, - `## sub header`, - ``, - `content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 3], [0, 6]); - }); - - test('Smart select last blockquote element under header then subheaders and their content', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> ${CURSOR}block`, - ``, - `paragraph`, - `## sub header`, - ``, - `content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [5, 5], [4, 5], [2, 5], [1, 7], [1, 10], [0, 10]); - }); - - test('Smart select content of subheader then subheader then content of main header then main header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `paragraph`, - `## sub header`, - ``, - ``, - `${CURSOR}`, - ``, - `### main header 2`, - `- content 2`, - `- content 2`, - `- content 2`, - `content 2`)); - - assertNestedLineNumbersEqual(ranges![0], [11, 11], [9, 12], [9, 17], [8, 17], [1, 17], [0, 17]); - }); - - test('Smart select last line content of subheader then subheader then content of main header then main header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `paragraph`, - `## sub header`, - ``, - ``, - ``, - ``, - `### main header 2`, - `- content 2`, - `- content 2`, - `- content 2`, - `- ${CURSOR}content 2`)); - - assertNestedLineNumbersEqual(ranges![0], [17, 17], [14, 17], [13, 17], [9, 17], [8, 17], [1, 17], [0, 17]); - }); - - test('Smart select last line content after content of subheader then subheader then content of main header then main header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `paragraph`, - `## sub header`, - ``, - ``, - ``, - ``, - `### main header 2`, - `- content 2`, - `- content 2`, - `- content 2`, - `- content 2${CURSOR}`)); - - assertNestedLineNumbersEqual(ranges![0], [17, 17], [14, 17], [13, 17], [9, 17], [8, 17], [1, 17], [0, 17]); - }); - - test('Smart select fenced code block then list then rest of content', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `- paragraph`, - `- ~~~`, - ` my`, - ` ${CURSOR}code`, - ` goes here`, - ` ~~~`, - `- content`, - `- content 2`, - `- content 2`, - `- content 2`, - `- content 2`)); - - assertNestedLineNumbersEqual(ranges![0], [9, 11], [8, 12], [8, 12], [7, 17], [1, 17], [0, 17]); - }); - - test('Smart select fenced code block then list then rest of content on fenced line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `- paragraph`, - `- ~~~${CURSOR}`, - ` my`, - ` code`, - ` goes here`, - ` ~~~`, - `- content`, - `- content 2`, - `- content 2`, - `- content 2`, - `- content 2`)); - - assertNestedLineNumbersEqual(ranges![0], [8, 12], [7, 17], [1, 17], [0, 17]); - }); - - test('Smart select without multiple ranges', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - ``, - `- ${CURSOR}paragraph`, - `- content`)); - - assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [1, 4], [0, 4]); - }); - - test('Smart select on second level of a list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 0`, - ` * level 1`, - ` * level 1`, - ` * level 2`, - ` * level 1`, - ` * level ${CURSOR}1`, - `* level 0`)); - - assertNestedLineNumbersEqual(ranges![0], [5, 5], [1, 5], [0, 5], [0, 6]); - }); - - test('Smart select on third level of a list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 0`, - ` * level 1`, - ` * level 1`, - ` * level ${CURSOR}2`, - ` * level 2`, - ` * level 1`, - ` * level 1`, - `* level 0`)); - assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [2, 4], [1, 6], [0, 6], [0, 7]); - }); - - test('Smart select level 2 then level 1', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 1`, - ` * level ${CURSOR}2`, - ` * level 2`, - `* level 1`)); - assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 2], [0, 2], [0, 3]); - }); - - test('Smart select last list item', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `- level 1`, - `- level 2`, - `- level 2`, - `- level ${CURSOR}1`)); - assertNestedLineNumbersEqual(ranges![0], [3, 3], [0, 3]); - }); - - test('Smart select without multiple ranges', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - ``, - `- ${CURSOR}paragraph`, - `- content`)); - - assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [1, 4], [0, 4]); - }); - - test('Smart select on second level of a list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 0`, - ` * level 1`, - ` * level 1`, - ` * level 2`, - ` * level 1`, - ` * level ${CURSOR}1`, - `* level 0`)); - - assertNestedLineNumbersEqual(ranges![0], [5, 5], [1, 5], [0, 5], [0, 6]); - }); - - test('Smart select on third level of a list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 0`, - ` * level 1`, - ` * level 1`, - ` * level ${CURSOR}2`, - ` * level 2`, - ` * level 1`, - ` * level 1`, - `* level 0`)); - assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [2, 4], [1, 6], [0, 6], [0, 7]); - }); - - test('Smart select level 2 then level 1', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 1`, - ` * level ${CURSOR}2`, - ` * level 2`, - `* level 1`)); - assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 2], [0, 2], [0, 3]); - }); - - test('Smart select bold', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `stuff here **new${CURSOR}item** and here` - )); - assertNestedRangesEqual(ranges![0], [0, 13, 0, 30], [0, 11, 0, 32], [0, 0, 0, 41]); - }); - - test('Smart select link', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `stuff here [text](https${CURSOR}://google.com) and here` - )); - assertNestedRangesEqual(ranges![0], [0, 18, 0, 46], [0, 17, 0, 47], [0, 11, 0, 47], [0, 0, 0, 56]); - }); - - test('Smart select brackets', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `stuff here [te${CURSOR}xt](https://google.com) and here` - )); - assertNestedRangesEqual(ranges![0], [0, 12, 0, 26], [0, 11, 0, 27], [0, 11, 0, 47], [0, 0, 0, 56]); - }); - - test('Smart select brackets under header in list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `- list`, - `paragraph`, - `## sub header`, - `- list`, - `- stuff here [te${CURSOR}xt](https://google.com) and here`, - `- list` - )); - assertNestedRangesEqual(ranges![0], [6, 14, 6, 28], [6, 13, 6, 29], [6, 13, 6, 49], [6, 0, 6, 58], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]); - }); - - test('Smart select link under header in list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `- list`, - `paragraph`, - `## sub header`, - `- list`, - `- stuff here [text](${CURSOR}https://google.com) and here`, - `- list` - )); - assertNestedRangesEqual(ranges![0], [6, 20, 6, 48], [6, 19, 6, 49], [6, 13, 6, 49], [6, 0, 6, 58], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]); - }); - - test('Smart select bold within list where multiple bold elements exists', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `- list`, - `paragraph`, - `## sub header`, - `- list`, - `- stuff here [text] **${CURSOR}items in here** and **here**`, - `- list` - )); - assertNestedRangesEqual(ranges![0], [6, 22, 6, 45], [6, 20, 6, 47], [6, 0, 6, 60], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]); - }); - - test('Smart select link in paragraph with multiple links', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `This[extension](https://marketplace.visualstudio.com/items?itemName=meganrogge.template-string-converter) addresses this [requ${CURSOR}est](https://github.com/microsoft/vscode/issues/56704) to convert Javascript/Typescript quotes to backticks when has been entered within a string.` - )); - assertNestedRangesEqual(ranges![0], [0, 123, 0, 140], [0, 122, 0, 141], [0, 122, 0, 191], [0, 0, 0, 283]); - }); - - test('Smart select bold link', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `**[extens${CURSOR}ion](https://google.com)**` - )); - assertNestedRangesEqual(ranges![0], [0, 3, 0, 22], [0, 2, 0, 23], [0, 2, 0, 43], [0, 2, 0, 43], [0, 0, 0, 45], [0, 0, 0, 45]); - }); - - test('Smart select inline code block', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `[\`code ${CURSOR} link\`]` - )); - assertNestedRangesEqual(ranges![0], [0, 2, 0, 22], [0, 1, 0, 23], [0, 0, 0, 24]); - }); - - test('Smart select link with inline code block text', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `[\`code ${CURSOR} link\`](http://example.com)` - )); - assertNestedRangesEqual(ranges![0], [0, 2, 0, 22], [0, 1, 0, 23], [0, 1, 0, 23], [0, 0, 0, 24], [0, 0, 0, 44], [0, 0, 0, 44]); - }); - - test('Smart select italic', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `*some nice ${CURSOR}text*` - )); - assertNestedRangesEqual(ranges![0], [0, 1, 0, 25], [0, 0, 0, 26], [0, 0, 0, 26]); - }); - - test('Smart select italic link', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `*[extens${CURSOR}ion](https://google.com)*` - )); - assertNestedRangesEqual(ranges![0], [0, 2, 0, 21], [0, 1, 0, 22], [0, 1, 0, 42], [0, 1, 0, 42], [0, 0, 0, 43], [0, 0, 0, 43]); - }); - - test('Smart select italic on end', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `*word1 word2 word3${CURSOR}*` - )); - assertNestedRangesEqual(ranges![0], [0, 1, 0, 28], [0, 0, 0, 29], [0, 0, 0, 29]); - }); - - test('Smart select italic then bold', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `outer text **bold words *italic ${CURSOR} words* bold words** outer text` - )); - assertNestedRangesEqual(ranges![0], [0, 25, 0, 48], [0, 24, 0, 49], [0, 13, 0, 60], [0, 11, 0, 62], [0, 0, 0, 73]); - }); - - test('Smart select bold then italic', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `outer text *italic words **bold ${CURSOR} words** italic words* outer text` - )); - assertNestedRangesEqual(ranges![0], [0, 27, 0, 48], [0, 25, 0, 50], [0, 12, 0, 63], [0, 11, 0, 64], [0, 0, 0, 75]); - }); - - test('Third level header from release notes', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `---`, - `Order: 60`, - `TOCTitle: October 2020`, - `PageTitle: Visual Studio Code October 2020`, - `MetaDescription: Learn what is new in the Visual Studio Code October 2020 Release (1.51)`, - `MetaSocialImage: 1_51/release-highlights.png`, - `Date: 2020-11-6`, - `DownloadVersion: 1.51.1`, - `---`, - `# October 2020 (version 1.51)`, - ``, - `**Update 1.51.1**: The update addresses these [issues](https://github.com/microsoft/vscode/issues?q=is%3Aissue+milestone%3A%22October+2020+Recovery%22+is%3Aclosed+).`, - ``, - ``, - ``, - `---`, - ``, - `Welcome to the October 2020 release of Visual Studio Code. As announced in the [October iteration plan](https://github.com/microsoft/vscode/issues/108473), we focused on housekeeping GitHub issues and pull requests as documented in our issue grooming guide.`, - ``, - `We also worked with our partners at GitHub on GitHub Codespaces, which ended up being more involved than originally anticipated. To that end, we'll continue working on housekeeping for part of the November iteration.`, - ``, - `During this housekeeping milestone, we also addressed several feature requests and community [pull requests](#thank-you). Read on to learn about new features and settings.`, - ``, - `## Workbench`, - ``, - `### More prominent pinned tabs`, - ``, - `${CURSOR}Pinned tabs will now always show their pin icon, even while inactive, to make them easier to identify. If an editor is both pinned and contains unsaved changes, the icon reflects both states.`, - ``, - `![Inactive pinned tabs showing pin icons](images/1_51/pinned-tabs.png)` - ) - ); - assertNestedRangesEqual(ranges![0], [27, 0, 27, 201], [26, 0, 29, 70], [25, 0, 29, 70], [24, 0, 29, 70], [23, 0, 29, 70], [10, 0, 29, 70], [9, 0, 29, 70]); - }); - -}); - - -function assertNestedLineNumbersEqual(range: vscode.SelectionRange, ...expectedRanges: [number, number][]) { - const lineage = getLineage(range); - assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length} ${getValues(lineage)}`); - for (let i = 0; i < lineage.length; i++) { - assertLineNumbersEqual(lineage[i], expectedRanges[i][0], expectedRanges[i][1], `parent at a depth of ${i}`); - } -} - -function assertNestedRangesEqual(range: vscode.SelectionRange, ...expectedRanges: [number, number, number, number][]) { - const lineage = getLineage(range); - assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length} ${getValues(lineage)}`); - for (let i = 0; i < lineage.length; i++) { - assertLineNumbersEqual(lineage[i], expectedRanges[i][0], expectedRanges[i][2], `parent at a depth of ${i}`); - assert(lineage[i].range.start.character === expectedRanges[i][1], `parent at a depth of ${i} on start char`); - assert(lineage[i].range.end.character === expectedRanges[i][3], `parent at a depth of ${i} on end char`); - } -} - -function getLineage(range: vscode.SelectionRange): vscode.SelectionRange[] { - const result: vscode.SelectionRange[] = []; - let currentRange: vscode.SelectionRange | undefined = range; - while (currentRange) { - result.push(currentRange); - currentRange = currentRange.parent; - } - return result; -} - -function getValues(ranges: vscode.SelectionRange[]): string[] { - return ranges.map(range => { - return range.range.start.line + ' ' + range.range.start.character + ' ' + range.range.end.line + ' ' + range.range.end.character; - }); -} - -function assertLineNumbersEqual(selectionRange: vscode.SelectionRange, startLine: number, endLine: number, message: string) { - assert.strictEqual(selectionRange.range.start.line, startLine, `failed on start line ${message}`); - assert.strictEqual(selectionRange.range.end.line, endLine, `failed on end line ${message}`); -} - -function getSelectionRangesForDocument(contents: string, pos?: vscode.Position[]): Promise { - const doc = new InMemoryDocument(testFileName, contents); - const workspace = new InMemoryMdWorkspace([doc]); - const engine = createNewMarkdownEngine(); - const provider = new MdSmartSelect(engine, new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const positions = pos ? pos : getCursorPositions(contents, doc); - return provider.provideSelectionRanges(doc, positions, new vscode.CancellationTokenSource().token); -} diff --git a/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts b/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts deleted file mode 100644 index 226ca4437e0..00000000000 --- a/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { TableOfContents } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { createNewMarkdownEngine } from './engine'; - - -const testFileName = vscode.Uri.file('test.md'); - -function createToc(doc: ITextDocument): Promise { - const engine = createNewMarkdownEngine(); - return TableOfContents.create(engine, doc); -} - -suite('markdown.TableOfContentsProvider', () => { - test('Lookup should not return anything for empty document', async () => { - const doc = new InMemoryDocument(testFileName, ''); - const provider = await createToc(doc); - - assert.strictEqual(provider.lookup(''), undefined); - assert.strictEqual(provider.lookup('foo'), undefined); - }); - - test('Lookup should not return anything for document with no headers', async () => { - const doc = new InMemoryDocument(testFileName, 'a *b*\nc'); - const provider = await createToc(doc); - - assert.strictEqual(provider.lookup(''), undefined); - assert.strictEqual(provider.lookup('foo'), undefined); - assert.strictEqual(provider.lookup('a'), undefined); - assert.strictEqual(provider.lookup('b'), undefined); - }); - - test('Lookup should return basic #header', async () => { - const doc = new InMemoryDocument(testFileName, `# a\nx\n# c`); - const provider = await createToc(doc); - - { - const entry = provider.lookup('a'); - assert.ok(entry); - assert.strictEqual(entry!.line, 0); - } - { - assert.strictEqual(provider.lookup('x'), undefined); - } - { - const entry = provider.lookup('c'); - assert.ok(entry); - assert.strictEqual(entry!.line, 2); - } - }); - - test('Lookups should be case in-sensitive', async () => { - const doc = new InMemoryDocument(testFileName, `# fOo\n`); - const provider = await createToc(doc); - - assert.strictEqual((provider.lookup('fOo'))!.line, 0); - assert.strictEqual((provider.lookup('foo'))!.line, 0); - assert.strictEqual((provider.lookup('FOO'))!.line, 0); - }); - - test('Lookups should ignore leading and trailing white-space, and collapse internal whitespace', async () => { - const doc = new InMemoryDocument(testFileName, `# f o o \n`); - const provider = await createToc(doc); - - assert.strictEqual((provider.lookup('f o o'))!.line, 0); - assert.strictEqual((provider.lookup(' f o o'))!.line, 0); - assert.strictEqual((provider.lookup(' f o o '))!.line, 0); - assert.strictEqual((provider.lookup('f o o'))!.line, 0); - assert.strictEqual((provider.lookup('f o o'))!.line, 0); - - assert.strictEqual(provider.lookup('f'), undefined); - assert.strictEqual(provider.lookup('foo'), undefined); - assert.strictEqual(provider.lookup('fo o'), undefined); - }); - - test('should handle special characters #44779', async () => { - const doc = new InMemoryDocument(testFileName, `# Indentação\n`); - const provider = await createToc(doc); - - assert.strictEqual((provider.lookup('indentação'))!.line, 0); - }); - - test('should handle special characters 2, #48482', async () => { - const doc = new InMemoryDocument(testFileName, `# Инструкция - Делай Раз, Делай Два\n`); - const provider = await createToc(doc); - - assert.strictEqual((provider.lookup('инструкция---делай-раз-делай-два'))!.line, 0); - }); - - test('should handle special characters 3, #37079', async () => { - const doc = new InMemoryDocument(testFileName, `## Header 2 -### Header 3 -## Заголовок 2 -### Заголовок 3 -### Заголовок Header 3 -## Заголовок`); - - const provider = await createToc(doc); - - assert.strictEqual((provider.lookup('header-2'))!.line, 0); - assert.strictEqual((provider.lookup('header-3'))!.line, 1); - assert.strictEqual((provider.lookup('Заголовок-2'))!.line, 2); - assert.strictEqual((provider.lookup('Заголовок-3'))!.line, 3); - assert.strictEqual((provider.lookup('Заголовок-header-3'))!.line, 4); - assert.strictEqual((provider.lookup('Заголовок'))!.line, 5); - }); - - test('Lookup should support suffixes for repeated headers', async () => { - const doc = new InMemoryDocument(testFileName, `# a\n# a\n## a`); - const provider = await createToc(doc); - - { - const entry = provider.lookup('a'); - assert.ok(entry); - assert.strictEqual(entry!.line, 0); - } - { - const entry = provider.lookup('a-1'); - assert.ok(entry); - assert.strictEqual(entry!.line, 1); - } - { - const entry = provider.lookup('a-2'); - assert.ok(entry); - assert.strictEqual(entry!.line, 2); - } - }); -}); diff --git a/extensions/markdown-language-features/src/test/util.ts b/extensions/markdown-language-features/src/test/util.ts index b9dc2241090..d50e9ca5db2 100644 --- a/extensions/markdown-language-features/src/test/util.ts +++ b/extensions/markdown-language-features/src/test/util.ts @@ -2,50 +2,7 @@ * 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 vscode from 'vscode'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; export const joinLines = (...args: string[]) => args.join(os.platform() === 'win32' ? '\r\n' : '\n'); - - -export const CURSOR = '$$CURSOR$$'; - -export function getCursorPositions(contents: string, doc: InMemoryDocument): vscode.Position[] { - const positions: vscode.Position[] = []; - let index = 0; - let wordLength = 0; - while (index !== -1) { - index = contents.indexOf(CURSOR, index + wordLength); - if (index !== -1) { - positions.push(doc.positionAt(index)); - } - wordLength = CURSOR.length; - } - return positions; -} - -export function workspacePath(...segments: string[]): vscode.Uri { - return vscode.Uri.joinPath(vscode.workspace.workspaceFolders![0].uri, ...segments); -} - -export function assertRangeEqual(expected: vscode.Range, actual: vscode.Range, message?: string) { - assert.strictEqual(expected.start.line, actual.start.line, message); - assert.strictEqual(expected.start.character, actual.start.character, message); - assert.strictEqual(expected.end.line, actual.end.line, message); - assert.strictEqual(expected.end.character, actual.end.character, message); -} - -export function withStore(fn: (this: Mocha.Context, store: DisposableStore) => Promise) { - return async function (this: Mocha.Context): Promise { - const store = new DisposableStore(); - try { - return await fn.call(this, store); - } finally { - store.dispose(); - } - }; -} diff --git a/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts deleted file mode 100644 index 3762a5a4ba1..00000000000 --- a/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts +++ /dev/null @@ -1,105 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbols'; -import { MdWorkspaceSymbolProvider } from '../languageFeatures/workspaceSymbols'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { IMdWorkspace } from '../workspace'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { withStore, workspacePath } from './util'; - -function getWorkspaceSymbols(store: DisposableStore, workspace: IMdWorkspace, query = ''): Promise { - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const symbolProvider = new MdDocumentSymbolProvider(tocProvider, nulLogger); - const workspaceSymbolProvider = store.add(new MdWorkspaceSymbolProvider(symbolProvider, workspace)); - return workspaceSymbolProvider.provideWorkspaceSymbols(query); -} - -suite('markdown.WorkspaceSymbolProvider', () => { - test('Should not return anything for empty workspace', withStore(async (store) => { - const workspace = store.add(new InMemoryMdWorkspace([])); - assert.deepStrictEqual(await getWorkspaceSymbols(store, workspace, ''), []); - })); - - test('Should return symbols from workspace with one markdown file', withStore(async (store) => { - const workspace = store.add(new InMemoryMdWorkspace([ - new InMemoryDocument(workspacePath('test.md'), `# header1\nabc\n## header2`) - ])); - - const symbols = await getWorkspaceSymbols(store, workspace, ''); - assert.strictEqual(symbols.length, 2); - assert.strictEqual(symbols[0].name, '# header1'); - assert.strictEqual(symbols[1].name, '## header2'); - })); - - test('Should return all content basic workspace', withStore(async (store) => { - const fileNameCount = 10; - const files: ITextDocument[] = []; - for (let i = 0; i < fileNameCount; ++i) { - const testFileName = workspacePath(`test${i}.md`); - files.push(new InMemoryDocument(testFileName, `# common\nabc\n## header${i}`)); - } - - const workspace = store.add(new InMemoryMdWorkspace(files)); - - const symbols = await getWorkspaceSymbols(store, workspace, ''); - assert.strictEqual(symbols.length, fileNameCount * 2); - })); - - test('Should update results when markdown file changes symbols', withStore(async (store) => { - const testFileName = workspacePath('test.md'); - const workspace = store.add(new InMemoryMdWorkspace([ - new InMemoryDocument(testFileName, `# header1`, 1 /* version */) - ])); - - assert.strictEqual((await getWorkspaceSymbols(store, workspace, '')).length, 1); - - // Update file - workspace.updateDocument(new InMemoryDocument(testFileName, `# new header\nabc\n## header2`, 2 /* version */)); - const newSymbols = await getWorkspaceSymbols(store, workspace, ''); - assert.strictEqual(newSymbols.length, 2); - assert.strictEqual(newSymbols[0].name, '# new header'); - assert.strictEqual(newSymbols[1].name, '## header2'); - })); - - test('Should remove results when file is deleted', withStore(async (store) => { - const testFileName = workspacePath('test.md'); - - const workspace = store.add(new InMemoryMdWorkspace([ - new InMemoryDocument(testFileName, `# header1`) - ])); - - assert.strictEqual((await getWorkspaceSymbols(store, workspace, '')).length, 1); - - // delete file - workspace.deleteDocument(testFileName); - const newSymbols = await getWorkspaceSymbols(store, workspace, ''); - assert.strictEqual(newSymbols.length, 0); - })); - - test('Should update results when markdown file is created', withStore(async (store) => { - const testFileName = workspacePath('test.md'); - - const workspace = store.add(new InMemoryMdWorkspace([ - new InMemoryDocument(testFileName, `# header1`) - ])); - - assert.strictEqual((await getWorkspaceSymbols(store, workspace, '')).length, 1); - - // Create file - workspace.createDocument(new InMemoryDocument(workspacePath('test2.md'), `# new header\nabc\n## header2`)); - const newSymbols = await getWorkspaceSymbols(store, workspace, ''); - assert.strictEqual(newSymbols.length, 3); - })); -}); diff --git a/extensions/markdown-language-features/src/types/textDocument.ts b/extensions/markdown-language-features/src/types/textDocument.ts index 5c49e065d40..f45614cc0cc 100644 --- a/extensions/markdown-language-features/src/types/textDocument.ts +++ b/extensions/markdown-language-features/src/types/textDocument.ts @@ -3,15 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type * as vscode from 'vscode'; - -/** - * Minimal version of {@link vscode.TextLine}. - */ -export interface ITextLine { - readonly text: string; - readonly isEmptyOrWhitespace: boolean; -} +import * as vscode from 'vscode'; /** * Minimal version of {@link vscode.TextDocument}. @@ -22,6 +14,9 @@ export interface ITextDocument { readonly lineCount: number; getText(range?: vscode.Range): string; - lineAt(line: number): ITextLine; positionAt(offset: number): vscode.Position; } + +export function getLine(doc: ITextDocument, line: number): string { + return doc.getText(new vscode.Range(line, 0, line, Number.MAX_VALUE)).replace(/\r?\n$/, ''); +} diff --git a/extensions/markdown-language-features/src/util/arrays.ts b/extensions/markdown-language-features/src/util/arrays.ts index 9e65508178e..10599259901 100644 --- a/extensions/markdown-language-features/src/util/arrays.ts +++ b/extensions/markdown-language-features/src/util/arrays.ts @@ -16,10 +16,3 @@ export function equals(one: ReadonlyArray, other: ReadonlyArray, itemEq return true; } - -/** - * @returns New array with all falsy values removed. The original array IS NOT modified. - */ -export function coalesce(array: ReadonlyArray): T[] { - return array.filter(e => !!e); -} diff --git a/extensions/markdown-language-features/src/util/async.ts b/extensions/markdown-language-features/src/util/async.ts index a3bca46d63c..e0de21edca6 100644 --- a/extensions/markdown-language-features/src/util/async.ts +++ b/extensions/markdown-language-features/src/util/async.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vscode'; - export interface ITask { (): T; } @@ -64,13 +62,3 @@ export class Delayer { } } } - -export function setImmediate(callback: (...args: any[]) => void, ...args: any[]): Disposable { - if (global.setImmediate) { - const handle = global.setImmediate(callback, ...args); - return { dispose: () => global.clearImmediate(handle) }; - } else { - const handle = setTimeout(callback, 0, ...args); - return { dispose: () => clearTimeout(handle) }; - } -} diff --git a/extensions/markdown-language-features/src/util/dispose.ts b/extensions/markdown-language-features/src/util/dispose.ts index ca78e4a821b..f222642908e 100644 --- a/extensions/markdown-language-features/src/util/dispose.ts +++ b/extensions/markdown-language-features/src/util/dispose.ts @@ -5,14 +5,6 @@ import * as vscode from 'vscode'; -export class MultiDisposeError extends Error { - constructor( - public readonly errors: any[] - ) { - super(`Encountered errors while disposing of store. Errors: [${errors.join(', ')}]`); - } -} - export function disposeAll(disposables: Iterable) { const errors: any[] = []; @@ -27,7 +19,7 @@ export function disposeAll(disposables: Iterable) { if (errors.length === 1) { throw errors[0]; } else if (errors.length > 1) { - throw new MultiDisposeError(errors); + throw new AggregateError(errors, 'Encountered errors while disposing of store'); } } @@ -61,22 +53,3 @@ export abstract class Disposable { return this._isDisposed; } } - -export class DisposableStore extends Disposable { - private readonly items = new Set(); - - public override dispose() { - super.dispose(); - disposeAll(this.items); - this.items.clear(); - } - - public add(item: T): T { - if (this.isDisposed) { - console.warn('Adding to disposed store. Item will be leaked'); - } - - this.items.add(item); - return item; - } -} diff --git a/extensions/markdown-language-features/src/util/file.ts b/extensions/markdown-language-features/src/util/file.ts index 6d5f22e95e0..9a4990a0585 100644 --- a/extensions/markdown-language-features/src/util/file.ts +++ b/extensions/markdown-language-features/src/util/file.ts @@ -5,23 +5,40 @@ import * as vscode from 'vscode'; import * as URI from 'vscode-uri'; +import { Schemes } from './schemes'; -const markdownFileExtensions = Object.freeze([ - '.md', - '.mkd', - '.mdwn', - '.mdown', - '.markdown', - '.markdn', - '.mdtxt', - '.mdtext', - '.workbook', +export const markdownFileExtensions = Object.freeze([ + 'md', + 'mkd', + 'mdwn', + 'mdown', + 'markdown', + 'markdn', + 'mdtxt', + 'mdtext', + 'workbook', ]); export function isMarkdownFile(document: vscode.TextDocument) { return document.languageId === 'markdown'; } -export function looksLikeMarkdownPath(resolvedHrefPath: vscode.Uri) { - return markdownFileExtensions.includes(URI.Utils.extname(resolvedHrefPath).toLowerCase()); +export function looksLikeMarkdownPath(resolvedHrefPath: vscode.Uri): boolean { + const doc = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === resolvedHrefPath.toString()); + if (doc) { + return isMarkdownFile(doc); + } + + if (resolvedHrefPath.scheme === Schemes.notebookCell) { + for (const notebook of vscode.workspace.notebookDocuments) { + for (const cell of notebook.getCells()) { + if (cell.kind === vscode.NotebookCellKind.Markup && isMarkdownFile(cell.document)) { + return true; + } + } + } + return false; + } + + return markdownFileExtensions.includes(URI.Utils.extname(resolvedHrefPath).toLowerCase().replace('.', '')); } diff --git a/extensions/markdown-language-features/src/util/hash.ts b/extensions/markdown-language-features/src/util/hash.ts deleted file mode 100644 index 36365f18fd6..00000000000 --- a/extensions/markdown-language-features/src/util/hash.ts +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -function numberHash(val: number, initialHashVal: number): number { - return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32 -} - -export function stringHash(s: string) { - let hashVal = numberHash(149417, 0); - for (let i = 0, length = s.length; i < length; i++) { - hashVal = numberHash(s.charCodeAt(i), hashVal); - } - return hashVal; -} diff --git a/extensions/markdown-language-features/src/util/inMemoryDocument.ts b/extensions/markdown-language-features/src/util/inMemoryDocument.ts index de29de21355..f626878deff 100644 --- a/extensions/markdown-language-features/src/util/inMemoryDocument.ts +++ b/extensions/markdown-language-features/src/util/inMemoryDocument.ts @@ -5,14 +5,12 @@ import * as vscode from 'vscode'; import { TextDocument } from 'vscode-languageserver-textdocument'; -import { ITextDocument, ITextLine } from '../types/textDocument'; +import { ITextDocument } from '../types/textDocument'; export class InMemoryDocument implements ITextDocument { private readonly _doc: TextDocument; - private lines: ITextLine[] | undefined; - constructor( public readonly uri: vscode.Uri, contents: string, public readonly version = 0, @@ -25,16 +23,6 @@ export class InMemoryDocument implements ITextDocument { return this._doc.lineCount; } - lineAt(index: any): ITextLine { - if (!this.lines) { - this.lines = this._doc.getText().split(/\r?\n/).map(text => ({ - text, - get isEmptyOrWhitespace() { return /^\s*$/.test(text); } - })); - } - return this.lines[index]; - } - positionAt(offset: number): vscode.Position { const pos = this._doc.positionAt(offset); return new vscode.Position(pos.line, pos.character); diff --git a/extensions/markdown-language-features/src/util/openDocumentLink.ts b/extensions/markdown-language-features/src/util/openDocumentLink.ts index d117aa15c3e..4e5ece8f328 100644 --- a/extensions/markdown-language-features/src/util/openDocumentLink.ts +++ b/extensions/markdown-language-features/src/util/openDocumentLink.ts @@ -3,101 +3,47 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as path from 'path'; import * as vscode from 'vscode'; -import * as uri from 'vscode-uri'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; -import { IMdWorkspace } from '../workspace'; -import { isMarkdownFile } from './file'; - -export interface OpenDocumentLinkArgs { - readonly parts: vscode.Uri; - readonly fragment: string; - readonly fromResource: vscode.Uri; -} +import { BaseLanguageClient } from 'vscode-languageclient'; +import * as proto from '../protocol'; enum OpenMarkdownLinks { beside = 'beside', currentGroup = 'currentGroup', } -export function resolveDocumentLink(href: string, markdownFile: vscode.Uri): vscode.Uri { - const [hrefPath, fragment] = href.split('#').map(c => decodeURIComponent(c)); +export class MdLinkOpener { - if (hrefPath[0] === '/') { - // Absolute path. Try to resolve relative to the workspace - const workspace = vscode.workspace.getWorkspaceFolder(markdownFile); - if (workspace) { - return vscode.Uri.joinPath(workspace.uri, hrefPath.slice(1)).with({ fragment }); + constructor( + private readonly client: BaseLanguageClient, + ) { } + + public async resolveDocumentLink(linkText: string, fromResource: vscode.Uri): Promise { + return this.client.sendRequest(proto.resolveLinkTarget, { linkText, uri: fromResource.toString() }); + } + + public async openDocumentLink(linkText: string, fromResource: vscode.Uri, viewColumn?: vscode.ViewColumn): Promise { + const resolved = await this.client.sendRequest(proto.resolveLinkTarget, { linkText, uri: fromResource.toString() }); + if (!resolved) { + return; } - } - // Relative path. Resolve relative to the md file - const dirnameUri = markdownFile.with({ path: path.dirname(markdownFile.path) }); - return vscode.Uri.joinPath(dirnameUri, hrefPath).with({ fragment }); -} + const uri = vscode.Uri.from(resolved.uri); + switch (resolved.kind) { + case 'external': + return vscode.commands.executeCommand('vscode.open', uri); -export async function openDocumentLink(tocProvider: MdTableOfContentsProvider, targetResource: vscode.Uri, fromResource: vscode.Uri): Promise { - const column = getViewColumn(fromResource); + case 'folder': + return vscode.commands.executeCommand('revealInExplorer', uri); - if (await tryNavigateToFragmentInActiveEditor(tocProvider, targetResource)) { - return; - } - - let targetResourceStat: vscode.FileStat | undefined; - try { - targetResourceStat = await vscode.workspace.fs.stat(targetResource); - } catch { - // noop - } - - if (typeof targetResourceStat === 'undefined') { - // We don't think the file exists. If it doesn't already have an extension, try tacking on a `.md` and using that instead - if (uri.Utils.extname(targetResource) === '') { - const dotMdResource = targetResource.with({ path: targetResource.path + '.md' }); - try { - const stat = await vscode.workspace.fs.stat(dotMdResource); - if (stat.type === vscode.FileType.File) { - await tryOpenMdFile(tocProvider, dotMdResource, column); - return; - } - } catch { - // noop + case 'file': { + return vscode.commands.executeCommand('vscode.open', uri, { + selection: resolved.position ? new vscode.Range(resolved.position.line, resolved.position.character, resolved.position.line, resolved.position.character) : undefined, + viewColumn: viewColumn ?? getViewColumn(fromResource), + }); } } - } else if (targetResourceStat.type === vscode.FileType.Directory) { - return vscode.commands.executeCommand('revealInExplorer', targetResource); } - - await tryOpenMdFile(tocProvider, targetResource, column); -} - -async function tryOpenMdFile(tocProvider: MdTableOfContentsProvider, resource: vscode.Uri, column: vscode.ViewColumn): Promise { - await vscode.commands.executeCommand('vscode.open', resource.with({ fragment: '' }), column); - return tryNavigateToFragmentInActiveEditor(tocProvider, resource); -} - -async function tryNavigateToFragmentInActiveEditor(tocProvider: MdTableOfContentsProvider, resource: vscode.Uri): Promise { - const notebookEditor = vscode.window.activeNotebookEditor; - if (notebookEditor?.notebook.uri.fsPath === resource.fsPath) { - if (await tryRevealLineInNotebook(tocProvider, notebookEditor, resource.fragment)) { - return true; - } - } - - const activeEditor = vscode.window.activeTextEditor; - if (activeEditor?.document.uri.fsPath === resource.fsPath) { - if (isMarkdownFile(activeEditor.document)) { - if (await tryRevealLineUsingTocFragment(tocProvider, activeEditor, resource.fragment)) { - return true; - } - } - tryRevealLineUsingLineFragment(activeEditor, resource.fragment); - return true; - } - - return false; } function getViewColumn(resource: vscode.Uri): vscode.ViewColumn { @@ -112,64 +58,3 @@ function getViewColumn(resource: vscode.Uri): vscode.ViewColumn { } } -async function tryRevealLineInNotebook(tocProvider: MdTableOfContentsProvider, editor: vscode.NotebookEditor, fragment: string): Promise { - const toc = await tocProvider.createForNotebook(editor.notebook); - const entry = toc.lookup(fragment); - if (!entry) { - return false; - } - - const cell = editor.notebook.getCells().find(cell => cell.document.uri.toString() === entry.sectionLocation.uri.toString()); - if (!cell) { - return false; - } - - const range = new vscode.NotebookRange(cell.index, cell.index); - editor.selection = range; - editor.revealRange(range); - return true; -} - -async function tryRevealLineUsingTocFragment(tocProvider: MdTableOfContentsProvider, editor: vscode.TextEditor, fragment: string): Promise { - const toc = await tocProvider.getForDocument(editor.document); - const entry = toc.lookup(fragment); - if (entry) { - const lineStart = new vscode.Range(entry.line, 0, entry.line, 0); - editor.selection = new vscode.Selection(lineStart.start, lineStart.end); - editor.revealRange(lineStart, vscode.TextEditorRevealType.AtTop); - return true; - } - return false; -} - -function tryRevealLineUsingLineFragment(editor: vscode.TextEditor, fragment: string): boolean { - const lineNumberFragment = fragment.match(/^L(\d+)$/i); - if (lineNumberFragment) { - const line = +lineNumberFragment[1] - 1; - if (!isNaN(line)) { - const lineStart = new vscode.Range(line, 0, line, 0); - editor.selection = new vscode.Selection(lineStart.start, lineStart.end); - editor.revealRange(lineStart, vscode.TextEditorRevealType.AtTop); - return true; - } - } - return false; -} - -export async function resolveUriToMarkdownFile(workspace: IMdWorkspace, resource: vscode.Uri): Promise { - try { - const doc = await workspace.getOrLoadMarkdownDocument(resource); - if (doc) { - return doc; - } - } catch { - // Noop - } - - // If no extension, try with `.md` extension - if (uri.Utils.extname(resource) === '') { - return workspace.getOrLoadMarkdownDocument(resource.with({ path: resource.path + '.md' })); - } - - return undefined; -} diff --git a/extensions/markdown-language-features/src/util/schemes.ts b/extensions/markdown-language-features/src/util/schemes.ts index e18f60ed81d..3eae0754ad2 100644 --- a/extensions/markdown-language-features/src/util/schemes.ts +++ b/extensions/markdown-language-features/src/util/schemes.ts @@ -3,33 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; - export const Schemes = Object.freeze({ - http: 'http', - https: 'https', file: 'file', untitled: 'untitled', mailto: 'mailto', - data: 'data', vscode: 'vscode', 'vscode-insiders': 'vscode-insiders', notebookCell: 'vscode-notebook-cell', }); -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/src/util/tableOfContentsWatcher.ts b/extensions/markdown-language-features/src/util/tableOfContentsWatcher.ts deleted file mode 100644 index 8bbbf26fafb..00000000000 --- a/extensions/markdown-language-features/src/util/tableOfContentsWatcher.ts +++ /dev/null @@ -1,89 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { MdTableOfContentsProvider, TableOfContents } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; -import { IMdWorkspace } from '../workspace'; -import { equals } from './arrays'; -import { Delayer } from './async'; -import { Disposable } from './dispose'; -import { ResourceMap } from './resourceMap'; - -/** - * Check if the items in a table of contents have changed. - * - * This only checks for changes in the entries themselves, not for any changes in their locations. - */ -function hasTableOfContentsChanged(a: TableOfContents, b: TableOfContents): boolean { - const aSlugs = a.entries.map(entry => entry.slug.value).sort(); - const bSlugs = b.entries.map(entry => entry.slug.value).sort(); - return !equals(aSlugs, bSlugs); -} - -export class MdTableOfContentsWatcher extends Disposable { - - private readonly _files = new ResourceMap<{ - readonly toc: TableOfContents; - }>(); - - private readonly _pending = new ResourceMap(); - - private readonly _onTocChanged = this._register(new vscode.EventEmitter<{ readonly uri: vscode.Uri }>); - public readonly onTocChanged = this._onTocChanged.event; - - private readonly delayer: Delayer; - - public constructor( - private readonly workspace: IMdWorkspace, - private readonly tocProvider: MdTableOfContentsProvider, - private readonly delay: number, - ) { - super(); - - this.delayer = this._register(new Delayer(delay)); - - this._register(this.workspace.onDidChangeMarkdownDocument(this.onDidChangeDocument, this)); - this._register(this.workspace.onDidCreateMarkdownDocument(this.onDidCreateDocument, this)); - this._register(this.workspace.onDidDeleteMarkdownDocument(this.onDidDeleteDocument, this)); - } - - private async onDidCreateDocument(document: ITextDocument) { - const toc = await this.tocProvider.getForDocument(document); - this._files.set(document.uri, { toc }); - } - - private async onDidChangeDocument(document: ITextDocument) { - if (this.delay > 0) { - this._pending.set(document.uri); - this.delayer.trigger(() => this.flushPending()); - } else { - this.updateForResource(document.uri); - } - } - - private onDidDeleteDocument(resource: vscode.Uri) { - this._files.delete(resource); - this._pending.delete(resource); - } - - private async flushPending() { - const pending = [...this._pending.keys()]; - this._pending.clear(); - - return Promise.all(pending.map(resource => this.updateForResource(resource))); - } - - private async updateForResource(resource: vscode.Uri) { - const existing = this._files.get(resource); - const newToc = await this.tocProvider.get(resource); - - if (!existing || hasTableOfContentsChanged(existing.toc, newToc)) { - this._onTocChanged.fire({ uri: resource }); - } - - this._files.set(resource, { toc: newToc }); - } -} diff --git a/extensions/markdown-language-features/src/util/workspaceCache.ts b/extensions/markdown-language-features/src/util/workspaceCache.ts deleted file mode 100644 index 8432675c87a..00000000000 --- a/extensions/markdown-language-features/src/util/workspaceCache.ts +++ /dev/null @@ -1,187 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { ITextDocument } from '../types/textDocument'; -import { IMdWorkspace } from '../workspace'; -import { Disposable } from './dispose'; -import { Lazy, lazy } from './lazy'; -import { ResourceMap } from './resourceMap'; - -class LazyResourceMap { - private readonly _map = new ResourceMap>>(); - - public has(resource: vscode.Uri): boolean { - return this._map.has(resource); - } - - public get(resource: vscode.Uri): Promise | undefined { - return this._map.get(resource)?.value; - } - - public set(resource: vscode.Uri, value: Lazy>) { - this._map.set(resource, value); - } - - public delete(resource: vscode.Uri) { - this._map.delete(resource); - } - - public entries(): Promise> { - return Promise.all(Array.from(this._map.entries(), async ([key, entry]) => { - return [key, await entry.value]; - })); - } -} - -/** - * Cache of information per-document in the workspace. - * - * The values are computed lazily and invalidated when the document changes. - */ -export class MdDocumentInfoCache extends Disposable { - - private readonly _cache = new LazyResourceMap(); - private readonly _loadingDocuments = new ResourceMap>(); - - public constructor( - private readonly workspace: IMdWorkspace, - private readonly getValue: (document: ITextDocument) => Promise, - ) { - super(); - - this._register(this.workspace.onDidChangeMarkdownDocument(doc => this.invalidate(doc))); - this._register(this.workspace.onDidDeleteMarkdownDocument(this.onDidDeleteDocument, this)); - } - - public async get(resource: vscode.Uri): Promise { - let existing = this._cache.get(resource); - if (existing) { - return existing; - } - - const doc = await this.loadDocument(resource); - if (!doc) { - return undefined; - } - - // Check if we have invalidated - existing = this._cache.get(resource); - if (existing) { - return existing; - } - - return this.resetEntry(doc)?.value; - } - - public async getForDocument(document: ITextDocument): Promise { - const existing = this._cache.get(document.uri); - if (existing) { - return existing; - } - return this.resetEntry(document).value; - } - - private loadDocument(resource: vscode.Uri): Promise { - const existing = this._loadingDocuments.get(resource); - if (existing) { - return existing; - } - - const p = this.workspace.getOrLoadMarkdownDocument(resource); - this._loadingDocuments.set(resource, p); - p.finally(() => { - this._loadingDocuments.delete(resource); - }); - return p; - } - - private resetEntry(document: ITextDocument): Lazy> { - const value = lazy(() => this.getValue(document)); - this._cache.set(document.uri, value); - return value; - } - - private invalidate(document: ITextDocument): void { - if (this._cache.has(document.uri)) { - this.resetEntry(document); - } - } - - private onDidDeleteDocument(resource: vscode.Uri) { - this._cache.delete(resource); - } -} - -/** - * Cache of information across all markdown files in the workspace. - * - * Unlike {@link MdDocumentInfoCache}, the entries here are computed eagerly for every file in the workspace. - * However the computation of the values is still lazy. - */ -export class MdWorkspaceInfoCache extends Disposable { - - private readonly _cache = new LazyResourceMap(); - private _init?: Promise; - - public constructor( - private readonly workspace: IMdWorkspace, - private readonly getValue: (document: ITextDocument) => Promise, - ) { - super(); - } - - public async entries(): Promise> { - await this.ensureInit(); - return this._cache.entries(); - } - - public async values(): Promise> { - await this.ensureInit(); - return Array.from(await this._cache.entries(), x => x[1]); - } - - public async getForDocs(docs: readonly ITextDocument[]): Promise { - for (const doc of docs) { - if (!this._cache.has(doc.uri)) { - this.update(doc); - } - } - - return Promise.all(docs.map(doc => this._cache.get(doc.uri) as Promise)); - } - - private async ensureInit(): Promise { - if (!this._init) { - this._init = this.populateCache(); - - this._register(this.workspace.onDidChangeMarkdownDocument(this.onDidChangeDocument, this)); - this._register(this.workspace.onDidCreateMarkdownDocument(this.onDidChangeDocument, this)); - this._register(this.workspace.onDidDeleteMarkdownDocument(this.onDidDeleteDocument, this)); - } - await this._init; - } - - private async populateCache(): Promise { - const markdownDocumentUris = await this.workspace.getAllMarkdownDocuments(); - for (const document of markdownDocumentUris) { - if (!this._cache.has(document.uri)) { - this.update(document); - } - } - } - - private update(document: ITextDocument): void { - this._cache.set(document.uri, lazy(() => this.getValue(document))); - } - - private onDidChangeDocument(document: ITextDocument) { - this.update(document); - } - - private onDidDeleteDocument(resource: vscode.Uri) { - this._cache.delete(resource); - } -} diff --git a/extensions/markdown-language-features/src/workspace.ts b/extensions/markdown-language-features/src/workspace.ts index 6d89b79e35d..c74a487c540 100644 --- a/extensions/markdown-language-features/src/workspace.ts +++ b/extensions/markdown-language-features/src/workspace.ts @@ -5,36 +5,16 @@ import * as vscode from 'vscode'; import { ITextDocument } from './types/textDocument'; -import { coalesce } from './util/arrays'; import { Disposable } from './util/dispose'; import { isMarkdownFile, looksLikeMarkdownPath } from './util/file'; import { InMemoryDocument } from './util/inMemoryDocument'; -import { Limiter } from './util/limiter'; import { ResourceMap } from './util/resourceMap'; /** * Provides set of markdown files in the current workspace. */ export interface IMdWorkspace { - /** - * Get list of all known markdown files. - */ - getAllMarkdownDocuments(): Promise>; - - /** - * Check if a document already exists in the workspace contents. - */ - hasMarkdownDocument(resource: vscode.Uri): boolean; - getOrLoadMarkdownDocument(resource: vscode.Uri): Promise; - - pathExists(resource: vscode.Uri): Promise; - - readDirectory(resource: vscode.Uri): Promise<[string, vscode.FileType][]>; - - readonly onDidChangeMarkdownDocument: vscode.Event; - readonly onDidCreateMarkdownDocument: vscode.Event; - readonly onDidDeleteMarkdownDocument: vscode.Event; } /** @@ -44,100 +24,27 @@ export interface IMdWorkspace { */ export class VsCodeMdWorkspace extends Disposable implements IMdWorkspace { - private readonly _onDidChangeMarkdownDocumentEmitter = this._register(new vscode.EventEmitter()); - private readonly _onDidCreateMarkdownDocumentEmitter = this._register(new vscode.EventEmitter()); - private readonly _onDidDeleteMarkdownDocumentEmitter = this._register(new vscode.EventEmitter()); - private _watcher: vscode.FileSystemWatcher | undefined; private readonly _documentCache = new ResourceMap(); private readonly utf8Decoder = new TextDecoder('utf-8'); - /** - * Reads and parses all .md documents in the workspace. - * Files are processed in batches, to keep the number of open files small. - * - * @returns Array of processed .md files. - */ - async getAllMarkdownDocuments(): Promise { - const maxConcurrent = 20; - - const foundFiles = new ResourceMap(); - const limiter = new Limiter(maxConcurrent); - - // Add files on disk - const resources = await vscode.workspace.findFiles('**/*.md', '**/node_modules/**'); - const onDiskResults = await Promise.all(resources.map(resource => { - return limiter.queue(async () => { - const doc = await this.getOrLoadMarkdownDocument(resource); - if (doc) { - foundFiles.set(resource); - } - return doc; - }); - })); - - // Add opened files (such as untitled files) - const openTextDocumentResults = await Promise.all(vscode.workspace.textDocuments - .filter(doc => !foundFiles.has(doc.uri) && this.isRelevantMarkdownDocument(doc))); - - return coalesce([...onDiskResults, ...openTextDocumentResults]); - } - - public get onDidChangeMarkdownDocument() { - this.ensureWatcher(); - return this._onDidChangeMarkdownDocumentEmitter.event; - } - - public get onDidCreateMarkdownDocument() { - this.ensureWatcher(); - return this._onDidCreateMarkdownDocumentEmitter.event; - } - - public get onDidDeleteMarkdownDocument() { - this.ensureWatcher(); - return this._onDidDeleteMarkdownDocumentEmitter.event; - } - - private ensureWatcher(): void { - if (this._watcher) { - return; - } + constructor() { + super(); this._watcher = this._register(vscode.workspace.createFileSystemWatcher('**/*.md')); this._register(this._watcher.onDidChange(async resource => { this._documentCache.delete(resource); - const document = await this.getOrLoadMarkdownDocument(resource); - if (document) { - this._onDidChangeMarkdownDocumentEmitter.fire(document); - } - })); - - this._register(this._watcher.onDidCreate(async resource => { - const document = await this.getOrLoadMarkdownDocument(resource); - if (document) { - this._onDidCreateMarkdownDocumentEmitter.fire(document); - } })); this._register(this._watcher.onDidDelete(resource => { this._documentCache.delete(resource); - this._onDidDeleteMarkdownDocumentEmitter.fire(resource); })); this._register(vscode.workspace.onDidOpenTextDocument(e => { this._documentCache.delete(e.uri); - if (this.isRelevantMarkdownDocument(e)) { - this._onDidCreateMarkdownDocumentEmitter.fire(e); - } - })); - - this._register(vscode.workspace.onDidChangeTextDocument(e => { - if (this.isRelevantMarkdownDocument(e.document)) { - this._onDidChangeMarkdownDocumentEmitter.fire(e.document); - } })); this._register(vscode.workspace.onDidCloseTextDocument(e => { @@ -177,22 +84,4 @@ export class VsCodeMdWorkspace extends Disposable implements IMdWorkspace { return undefined; } } - - public hasMarkdownDocument(resolvedHrefPath: vscode.Uri): boolean { - return this._documentCache.has(resolvedHrefPath); - } - - public async pathExists(target: vscode.Uri): Promise { - let targetResourceStat: vscode.FileStat | undefined; - try { - targetResourceStat = await vscode.workspace.fs.stat(target); - } catch { - return false; - } - return targetResourceStat.type === vscode.FileType.File || targetResourceStat.type === vscode.FileType.Directory; - } - - public async readDirectory(resource: vscode.Uri): Promise<[string, vscode.FileType][]> { - return vscode.workspace.fs.readDirectory(resource); - } } diff --git a/extensions/markdown-language-features/tsconfig.json b/extensions/markdown-language-features/tsconfig.json index 5b2636221ff..75edc8fdacf 100644 --- a/extensions/markdown-language-features/tsconfig.json +++ b/extensions/markdown-language-features/tsconfig.json @@ -6,7 +6,6 @@ "include": [ "src/**/*", "../../src/vscode-dts/vscode.d.ts", - "../../src/vscode-dts/vscode.proposed.textEditorDrop.d.ts", "../../src/vscode-dts/vscode.proposed.documentPaste.d.ts" ] } diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index 9052af7c6df..a484c602af0 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -2,6 +2,42 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/dompurify@^2.3.1": version "2.3.1" resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.1.tgz#2934adcd31c4e6b02676f9c22f9756e5091c04dd" @@ -59,16 +95,37 @@ resolved "https://registry.yarnpkg.com/@types/vscode-webview/-/vscode-webview-1.57.0.tgz#bad5194d45ae8d03afc1c0f67f71ff5e7a243bbf" integrity sha512-x3Cb/SMa1IwRHfSvKaZDZOTh4cNoG505c3NjTqGlMC082m++x/ETUmtYniDsw6SSmYzZXO8KBNhYxR0+VqymqA== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + dompurify@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" @@ -96,6 +153,13 @@ lodash.throttle@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + markdown-it-front-matter@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/markdown-it-front-matter/-/markdown-it-front-matter-0.2.1.tgz#dca49a827bb3cebb0528452c1d87dff276eb28dc" @@ -117,6 +181,13 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + morphdom@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/morphdom/-/morphdom-2.6.1.tgz#e868e24f989fa3183004b159aed643e628b4306e" @@ -127,22 +198,82 @@ picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +semver@^7.3.5: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== +vscode-jsonrpc@8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz#f239ed2cd6004021b6550af9fd9d3e47eee3cac9" + integrity sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ== + +vscode-languageclient@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz#f1f23ce8c8484aa11e4b7dfb24437d3e59bb61c6" + integrity sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q== + dependencies: + minimatch "^3.0.4" + semver "^7.3.5" + vscode-languageserver-protocol "3.17.2" + +vscode-languageserver-protocol@3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz#beaa46aea06ed061576586c5e11368a9afc1d378" + integrity sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg== + dependencies: + vscode-jsonrpc "8.0.2" + vscode-languageserver-types "3.17.2" + vscode-languageserver-textdocument@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-languageserver-textdocument@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.5.tgz#838769940ece626176ec5d5a2aa2d0aa69f5095c" + integrity sha512-1ah7zyQjKBudnMiHbZmxz5bYNM9KKZYz+5VQLj+yr8l+9w3g+WAhCkUkWbhMEdC5u0ub4Ndiye/fDyS8ghIKQg== + +vscode-languageserver-types@3.17.2, vscode-languageserver-types@^3.17.1, vscode-languageserver-types@^3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== + +vscode-markdown-languageservice@^0.0.0-alpha.10: + version "0.0.0-alpha.10" + resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.0.0-alpha.10.tgz#53b69c981eed7fd5efa155ab8c0f169995568681" + integrity sha512-rJ85nJ+d45yCz9lBhipavoWXz/vW5FknqqUpLqhe3/2xkrhxt8zcekhSoDepgkKFcTORAFV6g1SnnqxbVhX+uA== + dependencies: + picomatch "^2.3.1" + vscode-languageserver-textdocument "^1.0.5" + vscode-languageserver-types "^3.17.1" + vscode-nls "^5.0.1" + vscode-uri "^3.0.3" + +vscode-nls@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" + integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== + +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-uri@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== diff --git a/extensions/markdown-math/.gitignore b/extensions/markdown-math/.gitignore index 67c177886fb..93d9e664eae 100644 --- a/extensions/markdown-math/.gitignore +++ b/extensions/markdown-math/.gitignore @@ -1 +1,2 @@ notebook-out +languageService diff --git a/extensions/markdown-math/package.json b/extensions/markdown-math/package.json index b8ed2d88a74..045da771eb9 100644 --- a/extensions/markdown-math/package.json +++ b/extensions/markdown-math/package.json @@ -6,7 +6,7 @@ "icon": "icon.png", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.54.0" }, diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index 05603e468b2..d10085c4fc6 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -6,7 +6,7 @@ "icon": "media/icon.png", "version": "1.0.0", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.5.0" }, @@ -158,7 +158,7 @@ } }, "dependencies": { - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/merge-conflict/src/services.ts b/extensions/merge-conflict/src/services.ts index 932a665f4bc..9f58daad6f4 100644 --- a/extensions/merge-conflict/src/services.ts +++ b/extensions/merge-conflict/src/services.ts @@ -48,19 +48,6 @@ export default class ServiceWrapper implements vscode.Disposable { } createExtensionConfiguration(): interfaces.IExtensionConfiguration { - - // PRAGMATIC way to avoid conflicting with the new merge editor: when git opts into - // using the merge editor we disable this extension - for the merge editor but also - // for "other" editors - const gitConfig = vscode.workspace.getConfiguration('git'); - if (gitConfig.get('mergeEditor')) { - return { - enableCodeLens: false, - enableDecorations: false, - enableEditorOverview: false - }; - } - const workspaceConfiguration = vscode.workspace.getConfiguration(ConfigurationSectionName); const codeLensEnabled: boolean = workspaceConfiguration.get('codeLens.enabled', true); const decoratorsEnabled: boolean = workspaceConfiguration.get('decorators.enabled', true); diff --git a/extensions/merge-conflict/yarn.lock b/extensions/merge-conflict/yarn.lock index 699f1238a9b..90475ddc7e0 100644 --- a/extensions/merge-conflict/yarn.lock +++ b/extensions/merge-conflict/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index f206ce9e5a5..b40c7bb17b5 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -36,7 +36,7 @@ } ] }, - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "main": "./out/extension.js", "browser": "./dist/browser/extension.js", "scripts": { @@ -60,8 +60,8 @@ "sha.js": "2.4.11", "stream": "0.0.2", "uuid": "^8.2.0", - "@vscode/extension-telemetry": "0.6.1", - "vscode-nls": "^5.0.0" + "@vscode/extension-telemetry": "0.6.2", + "vscode-nls": "^5.1.0" }, "repository": { "type": "git", diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index bb22142e584..288157ba00d 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -11,7 +11,7 @@ import * as nls from 'vscode-nls'; import { v4 as uuid } from 'uuid'; import fetch, { Response } from 'node-fetch'; import Logger from './logger'; -import { toBase64UrlEncoding } from './utils'; +import { isSupportedEnvironment, toBase64UrlEncoding } from './utils'; import { sha256 } from './env/node/sha256'; import { BetterTokenStorage, IDidChangeInOtherWindowEvent } from './betterSecretStorage'; import { LoopbackAuthServer } from './authServer'; @@ -184,6 +184,9 @@ export class AzureActiveDirectoryService { if (!modifiedScopes.includes('profile')) { modifiedScopes.push('profile'); } + if (!modifiedScopes.includes('offline_access')) { + modifiedScopes.push('offline_access'); + } modifiedScopes = modifiedScopes.sort(); let modifiedScopesStr = modifiedScopes.join(' '); @@ -256,6 +259,9 @@ export class AzureActiveDirectoryService { if (!scopes.includes('profile')) { scopes.push('profile'); } + if (!scopes.includes('offline_access')) { + scopes.push('offline_access'); + } scopes = scopes.sort(); const scopeData: IScopeData = { scopes, @@ -319,13 +325,7 @@ export class AzureActiveDirectoryService { }, 5000); } - const token = await this.exchangeCodeForToken(codeToExchange, codeVerifier, scopeData); - if (token.expiresIn) { - this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER); - } - await this.setToken(token, scopeData); - Logger.info(`Login successful for scopes: ${scopeData.scopeStr}`); - const session = await this.convertToSession(token); + const session = await this.exchangeCodeForSession(codeToExchange, codeVerifier, scopeData); return session; } @@ -355,9 +355,11 @@ export class AzureActiveDirectoryService { const uri = vscode.Uri.parse(`${signInUrl}?${oauthStartQuery.toString()}`); vscode.env.openExternal(uri); + let inputBox: vscode.InputBox | undefined; const timeoutPromise = new Promise((_: (value: vscode.AuthenticationSession) => void, reject) => { const wait = setTimeout(() => { clearTimeout(wait); + inputBox?.dispose(); reject('Login timed out.'); }, 1000 * 60 * 5); }); @@ -369,7 +371,12 @@ export class AzureActiveDirectoryService { // before completing it. let existingPromise = this._codeExchangePromises.get(scopeData.scopeStr); if (!existingPromise) { - existingPromise = this.handleCodeResponse(scopeData); + if (isSupportedEnvironment(callbackUri)) { + existingPromise = this.handleCodeResponse(scopeData); + } else { + inputBox = vscode.window.createInputBox(); + existingPromise = this.handleCodeInputBox(inputBox, codeVerifier, scopeData); + } this._codeExchangePromises.set(scopeData.scopeStr, existingPromise); } @@ -659,13 +666,7 @@ export class AzureActiveDirectoryService { throw new Error('No available code verifier'); } - const token = await this.exchangeCodeForToken(code, verifier, scopeData); - if (token.expiresIn) { - this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER); - } - await this.setToken(token, scopeData); - - const session = await this.convertToSession(token); + const session = await this.exchangeCodeForSession(code, verifier, scopeData); resolve(session); } catch (err) { reject(err); @@ -680,8 +681,33 @@ export class AzureActiveDirectoryService { }); } - private async exchangeCodeForToken(code: string, codeVerifier: string, scopeData: IScopeData): Promise { + private async handleCodeInputBox(inputBox: vscode.InputBox, verifier: string, scopeData: IScopeData): Promise { + inputBox.ignoreFocusOut = true; + inputBox.title = localize('pasteCodeTitle', 'Microsoft Authentication'); + inputBox.prompt = localize('pasteCodePrompt', 'Provide the authorization code to complete the sign in flow.'); + inputBox.placeholder = localize('pasteCodePlaceholder', 'Paste authorization code here...'); + return new Promise((resolve: (value: vscode.AuthenticationSession) => void, reject) => { + inputBox.show(); + inputBox.onDidAccept(async () => { + const code = inputBox.value; + if (code) { + inputBox.dispose(); + const session = await this.exchangeCodeForSession(code, verifier, scopeData); + resolve(session); + } + }); + inputBox.onDidHide(() => { + if (!inputBox.value) { + inputBox.dispose(); + reject('Cancelled'); + } + }); + }); + } + + private async exchangeCodeForSession(code: string, codeVerifier: string, scopeData: IScopeData): Promise { Logger.info(`Exchanging login code for token for scopes: ${scopeData.scopeStr}`); + let token: IToken | undefined; try { const postData = querystring.stringify({ grant_type: 'authorization_code', @@ -698,11 +724,18 @@ export class AzureActiveDirectoryService { const json = await this.fetchTokenResponse(endpoint, postData, scopeData); Logger.info(`Exchanging login code for token (for scopes: ${scopeData.scopeStr}) succeeded!`); - return this.convertToTokenSync(json, scopeData); + token = this.convertToTokenSync(json, scopeData); } catch (e) { Logger.error(`Error exchanging code for token (for scopes ${scopeData.scopeStr}): ${e}`); throw e; } + + if (token.expiresIn) { + this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER); + } + await this.setToken(token, scopeData); + Logger.info(`Login successful for scopes: ${scopeData.scopeStr}`); + return await this.convertToSession(token); } private async fetchTokenResponse(endpoint: string, postData: string, scopeData: IScopeData): Promise { diff --git a/extensions/microsoft-authentication/src/utils.ts b/extensions/microsoft-authentication/src/utils.ts index 164f2236221..443bb2dc048 100644 --- a/extensions/microsoft-authentication/src/utils.ts +++ b/extensions/microsoft-authentication/src/utils.ts @@ -2,7 +2,40 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { env, UIKind, Uri } from 'vscode'; export function toBase64UrlEncoding(base64string: string) { return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); // Need to use base64url encoding } + +const LOCALHOST_ADDRESSES = ['localhost', '127.0.0.1', '0:0:0:0:0:0:0:1', '::1']; +function isLocalhost(uri: Uri): boolean { + if (!/^https?$/i.test(uri.scheme)) { + return false; + } + const host = uri.authority.split(':')[0]; + return LOCALHOST_ADDRESSES.indexOf(host) >= 0; +} + +export function isSupportedEnvironment(uri: Uri): boolean { + if (env.uiKind === UIKind.Desktop) { + return true; + } + // local development (localhost:* or 127.0.0.1:*) + if (isLocalhost(uri)) { + return true; + } + // At this point we should only ever see https + if (uri.scheme !== 'https') { + return false; + } + + return ( + // vscode.dev & insiders.vscode.dev + /(?:^|\.)vscode\.dev$/.test(uri.authority) || + // github.dev & codespaces + /(?:^|\.)github\.dev$/.test(uri.authority) || + // github.dev/codespaces local setup (github.localhost) + /(?:^|\.)github\.localhost$/.test(uri.authority) + ); +} diff --git a/extensions/microsoft-authentication/yarn.lock b/extensions/microsoft-authentication/yarn.lock index dea1d2e471a..6706f6a4aae 100644 --- a/extensions/microsoft-authentication/yarn.lock +++ b/extensions/microsoft-authentication/yarn.lock @@ -2,6 +2,42 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node-fetch@^2.5.7": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" @@ -39,10 +75,13 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.0.tgz#165aae4819ad2174a17476dbe66feebd549556c0" integrity sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" asynckit@^0.4.0: version "0.4.0" @@ -159,10 +198,10 @@ uuid@^8.2.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.2.0.tgz#cb10dd6b118e2dada7d0cd9730ba7417c93d920e" integrity sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== webidl-conversions@^3.0.0: version "3.0.1" diff --git a/extensions/notebook-renderers/package.json b/extensions/notebook-renderers/package.json index 15b6751e209..f78839bbeeb 100644 --- a/extensions/notebook-renderers/package.json +++ b/extensions/notebook-renderers/package.json @@ -17,7 +17,7 @@ "contributes": { "notebookRenderer": [ { - "id": "vscode-builtin-notebook-renderer", + "id": "vscode.builtin-renderer", "entrypoint": "./renderer-out/index.js", "displayName": "VS Code Builtin Notebook Output Renderer", "requiresMessaging": "never", diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index 1d6d75aa4f7..22dbb317a93 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -10,13 +10,21 @@ interface IDisposable { dispose(): void; } +interface HtmlRenderingHook { + /** + * Invoked after the output item has been rendered but before it has been appended to the document. + * + * @return A new `HTMLElement` or `undefined` to continue using the provided element. + */ + postRender(outputItem: OutputItem, element: HTMLElement): HTMLElement | undefined; +} + function clearContainer(container: HTMLElement) { while (container.firstChild) { container.removeChild(container.firstChild); } } - function renderImage(outputInfo: OutputItem, element: HTMLElement): IDisposable { const blob = new Blob([outputInfo.data()], { type: outputInfo.mime }); const src = URL.createObjectURL(blob); @@ -64,21 +72,28 @@ const domEval = (container: Element) => { } }; -function renderHTML(outputInfo: OutputItem, container: HTMLElement): void { +function renderHTML(outputInfo: OutputItem, container: HTMLElement, hooks: Iterable): void { clearContainer(container); + let element: HTMLElement = document.createElement('div'); const htmlContent = outputInfo.text(); - const element = document.createElement('div'); const trustedHtml = ttPolicy?.createHTML(htmlContent) ?? htmlContent; element.innerHTML = trustedHtml as string; + + for (const hook of hooks) { + element = hook.postRender(outputInfo, element) ?? element; + } + container.appendChild(element); domEval(element); } function renderJavascript(outputInfo: OutputItem, container: HTMLElement): void { - const str = outputInfo.text(); - const scriptVal = ``; + const script = document.createElement('script'); + script.type = 'module'; + script.textContent = outputInfo.text(); + const element = document.createElement('div'); - const trustedHtml = ttPolicy?.createHTML(scriptVal) ?? scriptVal; + const trustedHtml = ttPolicy?.createHTML(script.outerHTML) ?? script.outerHTML; element.innerHTML = trustedHtml as string; container.appendChild(element); domEval(element); @@ -167,6 +182,8 @@ function renderText(outputInfo: OutputItem, container: HTMLElement, ctx: Rendere export const activate: ActivationFunction = (ctx) => { const disposables = new Map(); + const htmlHooks = new Set(); + const latestContext = ctx as (RendererContext & { readonly settings: { readonly lineLimit: number } }); const style = document.createElement('style'); @@ -210,6 +227,7 @@ export const activate: ActivationFunction = (ctx) => { } `; document.body.appendChild(style); + return { renderOutputItem: (outputInfo, element) => { switch (outputInfo.mime) { @@ -220,7 +238,7 @@ export const activate: ActivationFunction = (ctx) => { return; } - renderHTML(outputInfo, element); + renderHTML(outputInfo, element, htmlHooks); } break; case 'application/javascript': @@ -267,8 +285,6 @@ export const activate: ActivationFunction = (ctx) => { default: break; } - - }, disposeOutputItem: (id: string | undefined) => { if (id) { @@ -276,6 +292,14 @@ export const activate: ActivationFunction = (ctx) => { } else { disposables.forEach(d => d.dispose()); } + }, + experimental_registerHtmlRenderingHook: (hook: HtmlRenderingHook): IDisposable => { + htmlHooks.add(hook); + return { + dispose: () => { + htmlHooks.delete(hook); + } + }; } }; }; diff --git a/extensions/notebook-renderers/tsconfig.json b/extensions/notebook-renderers/tsconfig.json index 23609811f3a..3472d5bbaa7 100644 --- a/extensions/notebook-renderers/tsconfig.json +++ b/extensions/notebook-renderers/tsconfig.json @@ -8,7 +8,6 @@ }, "include": [ "src/**/*", - "../../src/vscode-dts/vscode.d.ts", - "../../src/vscode-dts/vscode.proposed.notebookEditorEdit.d.ts", + "../../src/vscode-dts/vscode.d.ts" ] } diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 6df1a4835e7..9cc9ac5dedb 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -22,7 +22,7 @@ "jsonc-parser": "^2.2.1", "minimatch": "^3.0.4", "request-light": "^0.5.7", - "vscode-nls": "^5.0.0", + "vscode-nls": "^5.1.0", "which": "^2.0.2", "which-pm": "^2.0.0" }, @@ -298,6 +298,12 @@ "tags": [ "usesOnlineServices" ] + }, + "npm.scriptHover": { + "type": "boolean", + "description": "%config.npm.scriptHover%", + "default": true, + "scope": "window" } } }, diff --git a/extensions/npm/package.nls.json b/extensions/npm/package.nls.json index b0a4f06c01f..44f1d00f0f4 100644 --- a/extensions/npm/package.nls.json +++ b/extensions/npm/package.nls.json @@ -15,6 +15,7 @@ "config.npm.scriptExplorerExclude": "An array of regular expressions that indicate which scripts should be excluded from the NPM Scripts view.", "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.", + "config.npm.scriptHover": "Display hover with 'Run' and 'Debug' commands for scripts.", "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.", diff --git a/extensions/npm/src/features/packageJSONContribution.ts b/extensions/npm/src/features/packageJSONContribution.ts index a14f157b309..093fea678bc 100644 --- a/extensions/npm/src/features/packageJSONContribution.ts +++ b/extensions/npm/src/features/packageJSONContribution.ts @@ -314,9 +314,10 @@ export class PackageJSONContribution implements IJSONContribution { headers: { agent: USER_AGENT } }); const obj = JSON.parse(success.responseText); + const version = obj['dist-tags']?.latest || Object.keys(obj.versions).pop() || ''; return { description: obj.description || '', - version: Object.keys(obj.versions).pop(), + version, homepage: obj.homepage || '' }; } diff --git a/extensions/npm/src/npmScriptLens.ts b/extensions/npm/src/npmScriptLens.ts index 067209da334..2834d3e7639 100644 --- a/extensions/npm/src/npmScriptLens.ts +++ b/extensions/npm/src/npmScriptLens.ts @@ -71,7 +71,7 @@ export class NpmScriptLensProvider implements CodeLensProvider, Disposable { return []; } - const title = localize('codelens.debug', '{0} Debug', '$(debug-start)'); + const title = '$(debug-start) ' + localize('codelens.debug', 'Debug'); const cwd = path.dirname(document.uri.fsPath); if (this.lensLocation === 'top') { return [ diff --git a/extensions/npm/src/scriptHover.ts b/extensions/npm/src/scriptHover.ts index b8924bb25df..c96f3330d39 100644 --- a/extensions/npm/src/scriptHover.ts +++ b/extensions/npm/src/scriptHover.ts @@ -33,6 +33,7 @@ export function invalidateHoverScriptsCache(document?: TextDocument) { } export class NpmScriptHoverProvider implements HoverProvider { + private enabled: boolean; constructor(private context: ExtensionContext) { context.subscriptions.push(commands.registerCommand('npm.runScriptFromHover', this.runScriptFromHover, this)); @@ -40,9 +41,21 @@ export class NpmScriptHoverProvider implements HoverProvider { context.subscriptions.push(workspace.onDidChangeTextDocument((e) => { invalidateHoverScriptsCache(e.document); })); + + const isEnabled = () => workspace.getConfiguration('npm').get('scriptHover', true); + this.enabled = isEnabled(); + context.subscriptions.push(workspace.onDidChangeConfiguration((e) => { + if (e.affectsConfiguration('npm.scriptHover')) { + this.enabled = isEnabled(); + } + })); } public provideHover(document: TextDocument, position: Position, _token: CancellationToken): ProviderResult { + if (!this.enabled) { + return; + } + let hover: Hover | undefined = undefined; if (!cachedDocument || cachedDocument.fsPath !== document.uri.fsPath) { diff --git a/extensions/npm/yarn.lock b/extensions/npm/yarn.lock index bba9ffdbf39..3479f1c58b6 100644 --- a/extensions/npm/yarn.lock +++ b/extensions/npm/yarn.lock @@ -192,10 +192,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== which-pm@^2.0.0: version "2.0.0" diff --git a/extensions/package.json b/extensions/package.json index 2c89538c8a2..234c392efd9 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -4,7 +4,7 @@ "license": "MIT", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "4.7.3" + "typescript": "4.8.2" }, "scripts": { "postinstall": "node ./postinstall.mjs" diff --git a/extensions/php-language-features/package.json b/extensions/php-language-features/package.json index 8c0d484535b..8782b3d83b4 100644 --- a/extensions/php-language-features/package.json +++ b/extensions/php-language-features/package.json @@ -74,7 +74,7 @@ "watch": "npx gulp watch-extension:php-language-features" }, "dependencies": { - "vscode-nls": "^4.0.0", + "vscode-nls": "^5.1.0", "which": "^2.0.2" }, "devDependencies": { diff --git a/extensions/php-language-features/yarn.lock b/extensions/php-language-features/yarn.lock index 8dec3aadc63..62c8b33e55d 100644 --- a/extensions/php-language-features/yarn.lock +++ b/extensions/php-language-features/yarn.lock @@ -17,10 +17,10 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -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@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== which@^2.0.2: version "2.0.2" diff --git a/extensions/pug/cgmanifest.json b/extensions/pug/cgmanifest.json index e7bd7bccc09..341ab356db2 100644 --- a/extensions/pug/cgmanifest.json +++ b/extensions/pug/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "davidrios/pug-tmbundle", "repositoryUrl": "https://github.com/davidrios/pug-tmbundle", - "commitHash": "e67e895f6fb64932aa122e471000fa55d826bff6" + "commitHash": "8d7e93262a949afca023ee67ca8bb01a3b43e607" } }, "license": "MIT", diff --git a/extensions/pug/syntaxes/pug.tmLanguage.json b/extensions/pug/syntaxes/pug.tmLanguage.json index 108fc1ed1c6..4c1869c3258 100644 --- a/extensions/pug/syntaxes/pug.tmLanguage.json +++ b/extensions/pug/syntaxes/pug.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/davidrios/pug-tmbundle/commit/e67e895f6fb64932aa122e471000fa55d826bff6", + "version": "https://github.com/davidrios/pug-tmbundle/commit/8d7e93262a949afca023ee67ca8bb01a3b43e607", "name": "Pug", "scopeName": "text.pug", "patterns": [ @@ -656,7 +656,7 @@ }, { "begin": "=\\s*", - "end": "$|(?=,|(?:\\s+[^!%&*-+~|<>:?/])|\\))", + "end": "$|(?=,|(?:\\s+[^!%&*\\-+~|<>:?/])|\\))", "name": "attribute_value", "patterns": [ { @@ -677,8 +677,8 @@ ] }, { - "begin": "(?<=[%&*-+~|<>:?/])\\s+", - "end": "$|(?=,|(?:\\s+[^!%&*-+~|<>:?/])|\\))", + "begin": "(?<=[%&*\\-+~|<>:?/])\\s+", + "end": "$|(?=,|(?:\\s+[^!%&*\\-+~|<>:?/])|\\))", "name": "attribute_value2", "patterns": [ { diff --git a/extensions/razor/package.json b/extensions/razor/package.json index 13eb84206c4..ace1ed7f959 100644 --- a/extensions/razor/package.json +++ b/extensions/razor/package.json @@ -8,9 +8,6 @@ "engines": { "vscode": "0.10.x" }, - "scripts": { - "update-grammar": "node ../node_modules/vscode-grammar-updater/bin demyte/language-cshtml grammars/cshtml.json ./syntaxes/cshtml.tmLanguage.json" - }, "contributes": { "languages": [ { diff --git a/extensions/references-view/package.json b/extensions/references-view/package.json index f5c0a910f1e..4176cda3d1a 100644 --- a/extensions/references-view/package.json +++ b/extensions/references-view/package.json @@ -407,7 +407,7 @@ "watch": "npx gulp watch-extension:references-view" }, "dependencies": { - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/references-view/src/extension.ts b/extensions/references-view/src/extension.ts index 94c258cd73c..4cd47866fe2 100644 --- a/extensions/references-view/src/extension.ts +++ b/extensions/references-view/src/extension.ts @@ -22,5 +22,9 @@ export function activate(context: vscode.ExtensionContext): SymbolTree { tree.setInput(input); } - return { setInput }; + function getInput(): SymbolTreeInput | undefined { + return tree.getInput(); + } + + return { setInput, getInput }; } diff --git a/extensions/references-view/src/references-view.d.ts b/extensions/references-view/src/references-view.d.ts index 9ec370029a7..cafe77f9cb4 100644 --- a/extensions/references-view/src/references-view.d.ts +++ b/extensions/references-view/src/references-view.d.ts @@ -6,9 +6,10 @@ import * as vscode from 'vscode'; /** - * This interface describes the shape for the references viewlet API. It consists - * of a single `setInput` function which must be called with a full implementation - * of the `SymbolTreeInput`-interface. To acquire this API use the default mechanics, e.g: + * This interface describes the shape for the references viewlet API. It includes + * a single `setInput` function which must be called with a full implementation + * of the `SymbolTreeInput`-interface. You can also use `getInput` function to + * get the current `SymbolTreeInput`. To acquire this API use the default mechanics, e.g: * * ```ts * // get references viewlet API @@ -16,7 +17,8 @@ import * as vscode from 'vscode'; * * // instantiate and set input which updates the view * const myInput: SymbolTreeInput = ... - * api.setInput(myInput) + * api.setInput(myInput); + * const currentInput = api.getInput(); * ``` */ export interface SymbolTree { @@ -27,6 +29,13 @@ export interface SymbolTree { * @param input A symbol tree input object */ setInput(input: SymbolTreeInput): void; + + /** + * Get the contents of the references viewlet. + * + * @returns The current symbol tree input object + */ + getInput(): SymbolTreeInput | undefined; } /** diff --git a/extensions/references-view/src/types/index.ts b/extensions/references-view/src/types/index.ts index ed2e4b872f6..5d1fc2f3318 100644 --- a/extensions/references-view/src/types/index.ts +++ b/extensions/references-view/src/types/index.ts @@ -19,13 +19,15 @@ export function register(tree: SymbolsTree, context: vscode.ExtensionContext): v } } - function setTypeHierarchyDirection(value: TypeHierarchyDirection, anchor: TypeItem | unknown) { + function setTypeHierarchyDirection(value: TypeHierarchyDirection, anchor: TypeItem | vscode.Location | unknown) { direction.value = value; let newInput: TypesTreeInput | undefined; const oldInput = tree.getInput(); if (anchor instanceof TypeItem) { newInput = new TypesTreeInput(new vscode.Location(anchor.item.uri, anchor.item.selectionRange.start), direction.value); + } else if (anchor instanceof vscode.Location) { + newInput = new TypesTreeInput(anchor, direction.value); } else if (oldInput instanceof TypesTreeInput) { newInput = new TypesTreeInput(oldInput.location, direction.value); } @@ -36,8 +38,8 @@ export function register(tree: SymbolsTree, context: vscode.ExtensionContext): v context.subscriptions.push( vscode.commands.registerCommand('references-view.showTypeHierarchy', showTypeHierarchy), - vscode.commands.registerCommand('references-view.showSupertypes', (item: TypeItem | unknown) => setTypeHierarchyDirection(TypeHierarchyDirection.Supertypes, item)), - vscode.commands.registerCommand('references-view.showSubtypes', (item: TypeItem | unknown) => setTypeHierarchyDirection(TypeHierarchyDirection.Subtypes, item)), + vscode.commands.registerCommand('references-view.showSupertypes', (item: TypeItem | vscode.Location | unknown) => setTypeHierarchyDirection(TypeHierarchyDirection.Supertypes, item)), + vscode.commands.registerCommand('references-view.showSubtypes', (item: TypeItem | vscode.Location | unknown) => setTypeHierarchyDirection(TypeHierarchyDirection.Subtypes, item)), vscode.commands.registerCommand('references-view.removeTypeItem', removeTypeItem) ); } diff --git a/extensions/references-view/yarn.lock b/extensions/references-view/yarn.lock index 0f041514ffc..76eaba8dd6f 100644 --- a/extensions/references-view/yarn.lock +++ b/extensions/references-view/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.33.tgz#566713b1b626f781c5c58fe3531307283e00720c" integrity sha512-0PJ0vg+JyU0MIan58IOIFRtSvsb7Ri+7Wltx2qAg94eMOrpg4+uuP3aUHCpxXc1i0jCXiC+zIamSZh3l9AbcQA== -vscode-nls@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" - integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/scss/cgmanifest.json b/extensions/scss/cgmanifest.json index 12247769ce2..a67a4f54609 100644 --- a/extensions/scss/cgmanifest.json +++ b/extensions/scss/cgmanifest.json @@ -6,12 +6,12 @@ "git": { "name": "atom/language-sass", "repositoryUrl": "https://github.com/atom/language-sass", - "commitHash": "f52ab12f7f9346cc2568129d8c4419bd3d506b47" + "commitHash": "303bbf0c250fe380b9e57375598cfd916110758b" } }, "license": "MIT", "description": "The file syntaxes/scss.json was derived from the Atom package https://github.com/atom/language-sass which was originally converted from the TextMate bundle https://github.com/alexsancho/SASS.tmbundle.", - "version": "0.62.1" + "version": "0.61.4" } ], "version": 1 diff --git a/extensions/shared.webpack.config.js b/extensions/shared.webpack.config.js index a33fa89ce30..a8f24c1a572 100644 --- a/extensions/shared.webpack.config.js +++ b/extensions/shared.webpack.config.js @@ -13,7 +13,7 @@ const fs = require('fs'); const merge = require('merge-options'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const { NLSBundlePlugin } = require('vscode-nls-dev/lib/webpack-bundler'); -const { DefinePlugin } = require('webpack'); +const { DefinePlugin, optimize } = require('webpack'); function withNodeDefaults(/**@type WebpackConfig*/extConfig) { /** @type WebpackConfig */ @@ -70,6 +70,10 @@ function withNodeDefaults(/**@type WebpackConfig*/extConfig) { return merge(defaultConfig, extConfig); } +/** + * + * @param {string} context + */ function nodePlugins(context) { // Need to find the top-most `package.json` file const folderName = path.relative(__dirname, context).split(/[\\\/]/)[0]; @@ -108,21 +112,32 @@ function withBrowserDefaults(/**@type WebpackConfig*/extConfig, /** @type Additi rules: [{ test: /\.ts$/, exclude: /node_modules/, - use: [{ - // configure TypeScript loader: - // * enable sources maps for end-to-end source maps - loader: 'ts-loader', - options: { - compilerOptions: { - 'sourceMap': true, - }, - ...(additionalOptions ? {} : { configFile: additionalOptions.configFile }) - } - }] + use: [ + // TODO: bring this back once vscode-nls-dev supports browser + // { + // // vscode-nls-dev loader: + // // * rewrite nls-calls + // loader: 'vscode-nls-dev/lib/webpack-loader', + // options: { + // base: path.join(extConfig.context, 'src') + // } + // }, + { + // configure TypeScript loader: + // * enable sources maps for end-to-end source maps + loader: 'ts-loader', + options: { + compilerOptions: { + 'sourceMap': true, + }, + ...(additionalOptions ? {} : { configFile: additionalOptions.configFile }) + } + }] }] }, externals: { 'vscode': 'commonjs vscode', // ignored because it doesn't exist, + 'vscode-nls-web-data': 'commonjs vscode-nls-web-data', // ignored because this is injected by the webworker extension host 'applicationinsights-native-metrics': 'commonjs applicationinsights-native-metrics', // ignored because we don't ship native module '@opentelemetry/tracing': 'commonjs @opentelemetry/tracing' // ignored because we don't ship this module }, @@ -138,27 +153,40 @@ function withBrowserDefaults(/**@type WebpackConfig*/extConfig, /** @type Additi }, // yes, really source maps devtool: 'source-map', - plugins: browserPlugins + plugins: browserPlugins(extConfig.context) }; return merge(defaultConfig, extConfig); } -const browserPlugins = [ - new CopyWebpackPlugin({ - patterns: [ - { from: 'src', to: '.', globOptions: { ignore: ['**/test/**', '**/*.ts'] }, noErrorOnMissing: true } - ] - }), - new DefinePlugin({ - 'process.platform': JSON.stringify('web'), - 'process.env': JSON.stringify({}), - 'process.env.BROWSER_ENV': JSON.stringify('true') - }) -]; - - - +/** + * + * @param {string} context + */ +function browserPlugins(context) { + // Need to find the top-most `package.json` file + // const folderName = path.relative(__dirname, context).split(/[\\\/]/)[0]; + // const pkgPath = path.join(__dirname, folderName, 'package.json'); + // const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + // const id = `${pkg.publisher}.${pkg.name}`; + return [ + new optimize.LimitChunkCountPlugin({ + maxChunks: 1 + }), + new CopyWebpackPlugin({ + patterns: [ + { from: 'src', to: '.', globOptions: { ignore: ['**/test/**', '**/*.ts'] }, noErrorOnMissing: true } + ] + }), + new DefinePlugin({ + 'process.platform': JSON.stringify('web'), + 'process.env': JSON.stringify({}), + 'process.env.BROWSER_ENV': JSON.stringify('true') + }), + // TODO: bring this back once vscode-nls-dev supports browser + // new NLSBundlePlugin(id) + ]; +} module.exports = withNodeDefaults; module.exports.node = withNodeDefaults; diff --git a/extensions/shellscript/package.json b/extensions/shellscript/package.json index 6bb0131dd30..7fa55ea680c 100644 --- a/extensions/shellscript/package.json +++ b/extensions/shellscript/package.json @@ -19,6 +19,7 @@ "Shell Script", "shellscript", "bash", + "fish", "sh", "zsh", "ksh", @@ -45,6 +46,7 @@ ".zlogout", ".zshenv", ".zsh-theme", + ".fish", ".ksh", ".csh", ".cshrc", @@ -65,7 +67,7 @@ "bashrc_Apple_Terminal", "zshrc_Apple_Terminal" ], - "firstLine": "^#!.*\\b(bash|zsh|sh|ksh|dtksh|pdksh|mksh|ash|dash|yash|sh|csh|jcsh|tcsh|itcsh).*|^#\\s*-\\*-[^*]*mode:\\s*shell-script[^*]*-\\*-", + "firstLine": "^#!.*\\b(bash|fish|zsh|sh|ksh|dtksh|pdksh|mksh|ash|dash|yash|sh|csh|jcsh|tcsh|itcsh).*|^#\\s*-\\*-[^*]*mode:\\s*shell-script[^*]*-\\*-", "configuration": "./language-configuration.json", "mimetypes": [ "text/x-shellscript" diff --git a/extensions/simple-browser/.vscodeignore b/extensions/simple-browser/.vscodeignore index ec298ce1768..d1006b25b79 100644 --- a/extensions/simple-browser/.vscodeignore +++ b/extensions/simple-browser/.vscodeignore @@ -11,3 +11,4 @@ cgmanifest.json yarn.lock preview-src/** webpack.config.js +esbuild-preview.js diff --git a/extensions/simple-browser/package.json b/extensions/simple-browser/package.json index 7ba03888339..fe3f4de2a5f 100644 --- a/extensions/simple-browser/package.json +++ b/extensions/simple-browser/package.json @@ -9,7 +9,7 @@ "icon": "media/icon.png", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.53.0" }, @@ -67,8 +67,8 @@ "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, "dependencies": { - "@vscode/extension-telemetry": "0.6.1", - "vscode-nls": "^5.0.0" + "@vscode/extension-telemetry": "0.6.2", + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/vscode-webview": "^1.57.0", diff --git a/extensions/simple-browser/src/extension.ts b/extensions/simple-browser/src/extension.ts index ff3649c7baf..63131a43bcf 100644 --- a/extensions/simple-browser/src/extension.ts +++ b/extensions/simple-browser/src/extension.ts @@ -32,6 +32,9 @@ const enabledHosts = new Set([ '::' ]); +const IPv6Localhost = /0\:0\:0\:0\:0\:0\:0\:1|\:\:1/; +const IPv6AllInterfaces = /0\:0\:0\:0\:0\:0\:0\:0|\:\:/; + const openerId = 'simpleBrowser.open'; export function activate(context: vscode.ExtensionContext) { @@ -67,7 +70,8 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.window.registerExternalUriOpener(openerId, { canOpenExternalUri(uri: vscode.Uri) { - const originalUri = new URL(uri.toString()); + // We have to replace the IPv6 hosts with IPv4 because URL can't handle IPv6. + const originalUri = new URL(uri.toString().replace(IPv6Localhost, '127.0.0.1').replace(IPv6AllInterfaces, '0.0.0.0')); if (enabledHosts.has(originalUri.hostname)) { return isWeb() ? vscode.ExternalUriOpenerPriority.Default diff --git a/extensions/simple-browser/yarn.lock b/extensions/simple-browser/yarn.lock index 0a897c7ddba..32215e9059b 100644 --- a/extensions/simple-browser/yarn.lock +++ b/extensions/simple-browser/yarn.lock @@ -2,22 +2,61 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/vscode-webview@^1.57.0": version "1.57.0" resolved "https://registry.yarnpkg.com/@types/vscode-webview/-/vscode-webview-1.57.0.tgz#bad5194d45ae8d03afc1c0f67f71ff5e7a243bbf" integrity sha512-x3Cb/SMa1IwRHfSvKaZDZOTh4cNoG505c3NjTqGlMC082m++x/ETUmtYniDsw6SSmYzZXO8KBNhYxR0+VqymqA== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" vscode-codicons@^0.0.14: version "0.0.14" resolved "https://registry.yarnpkg.com/vscode-codicons/-/vscode-codicons-0.0.14.tgz#e0d05418e2e195564ff6f6a2199d70415911c18f" integrity sha512-6CEH5KT9ct5WMw7n5dlX7rB8ya4CUI2FSq1Wk36XaW+c5RglFtAanUV0T+gvZVVFhl/WxfjTvFHq06Hz9c1SLA== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/sql/cgmanifest.json b/extensions/sql/cgmanifest.json index f1d6e04e5ad..b40cb39a6e3 100644 --- a/extensions/sql/cgmanifest.json +++ b/extensions/sql/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "microsoft/vscode-mssql", "repositoryUrl": "https://github.com/microsoft/vscode-mssql", - "commitHash": "c98518dd7418ddfb6f35676e14cf12791b0a235d" + "commitHash": "b8b58864526c048002b7c3964bdac8aac3713bd9" } }, "license": "MIT", - "version": "1.10.1" + "version": "1.16.0" } ], "version": 1 diff --git a/extensions/sql/syntaxes/sql.tmLanguage.json b/extensions/sql/syntaxes/sql.tmLanguage.json index ec0e461d9f8..26575ff4549 100644 --- a/extensions/sql/syntaxes/sql.tmLanguage.json +++ b/extensions/sql/syntaxes/sql.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/microsoft/vscode-mssql/commit/c98518dd7418ddfb6f35676e14cf12791b0a235d", + "version": "https://github.com/microsoft/vscode-mssql/commit/b8b58864526c048002b7c3964bdac8aac3713bd9", "name": "SQL", "scopeName": "source.sql", "patterns": [ @@ -191,7 +191,7 @@ "name": "keyword.operator.concatenator.sql" }, { - "match": "(?i)\\b(avg|checksum_agg|count|count_big|grouping|grouping_id|max|min|sum|stdev|stdevp|var|varp)\\b", + "match": "(?i)\\b(aggregate|approx_count_distinct|avg|checksum_agg|count|count_big|grouping|grouping_id|max|min|sum|stdev|stdevp|var|varp)\\b", "name": "support.function.aggregate.sql" }, { @@ -202,14 +202,26 @@ "match": "(?i)\\b(cast|convert|parse|try_cast|try_convert|try_parse)\\b", "name": "support.function.conversion.sql" }, + { + "match": "(?i)\\b(collationproperty|tertiary_weights)\\b", + "name": "support.function.collation.sql" + }, + { + "match": "(?i)\\b(asymkey_id|asymkeyproperty|certproperty|cert_id|crypt_gen_random|decryptbyasymkey|decryptbycert|decryptbykey|decryptbykeyautoasymkey|decryptbykeyautocert|decryptbypassphrase|encryptbyasymkey|encryptbycert|encryptbykey|encryptbypassphrase|hashbytes|is_objectsigned|key_guid|key_id|key_name|signbyasymkey|signbycert|symkeyproperty|verifysignedbycert|verifysignedbyasymkey)\\b", + "name": "support.function.cryptographic.sql" + }, { "match": "(?i)\\b(cursor_status)\\b", "name": "support.function.cursor.sql" }, { - "match": "(?i)\\b(sysdatetime|sysdatetimeoffset|sysutcdatetime|current_time(stamp)?|getdate|getutcdate|datename|datepart|day|month|year|datefromparts|datetime2fromparts|datetimefromparts|datetimeoffsetfromparts|smalldatetimefromparts|timefromparts|datediff|dateadd|eomonth|switchoffset|todatetimeoffset|isdate)\\b", + "match": "(?i)\\b(sysdatetime|sysdatetimeoffset|sysutcdatetime|current_time(stamp)?|getdate|getutcdate|datename|datepart|day|month|year|datefromparts|datetime2fromparts|datetimefromparts|datetimeoffsetfromparts|smalldatetimefromparts|timefromparts|datediff|dateadd|eomonth|switchoffset|todatetimeoffset|isdate|date_bucket)\\b", "name": "support.function.datetime.sql" }, + { + "match": "(?i)\\b(datalength|ident_current|ident_incr|ident_seed|identity|sql_variant_property)\\b", + "name": "support.function.datatype.sql" + }, { "match": "(?i)\\b(coalesce|nullif)\\b", "name": "support.function.expression.sql" @@ -219,7 +231,11 @@ "name": "support.function.globalvar.sql" }, { - "match": "(?i)\\b(choose|iif)\\b", + "match": "(?i)\\b(json|isjson|json_object|json_array|json_value|json_query|json_modify|json_path_exists)\\b", + "name": "support.function.json.sql" + }, + { + "match": "(?i)\\b(choose|iif|greatest|least)\\b", "name": "support.function.logical.sql" }, { @@ -235,7 +251,7 @@ "name": "support.function.ranking.sql" }, { - "match": "(?i)\\b(opendatasource|openrowset|openquery|openxml)\\b", + "match": "(?i)\\b(generate_series|opendatasource|openjson|openrowset|openquery|openxml|predict|string_split)\\b", "name": "support.function.rowset.sql" }, { diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index aa48d9724fe..3157d39b234 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -7,7 +7,11 @@ } }, { - "scope": ["meta.embedded", "source.groovy.embedded"], + "scope": [ + "meta.embedded", + "source.groovy.embedded", + "string meta.image.inline.markdown" + ], "settings": { "foreground": "#6688cc" } diff --git a/extensions/theme-defaults/themes/dark_vs.json b/extensions/theme-defaults/themes/dark_vs.json index 8072b0bdd6e..7b3c8d5e6fd 100644 --- a/extensions/theme-defaults/themes/dark_vs.json +++ b/extensions/theme-defaults/themes/dark_vs.json @@ -20,13 +20,15 @@ "sideBarSectionHeader.background": "#0000", "sideBarSectionHeader.border": "#ccc3", "tab.lastPinnedBorder": "#ccc3", - "list.activeSelectionIconForeground": "#FFF" + "list.activeSelectionIconForeground": "#FFF", + "terminal.inactiveSelectionBackground": "#3A3D41", }, "tokenColors": [ { "scope": [ "meta.embedded", - "source.groovy.embedded" + "source.groovy.embedded", + "string meta.image.inline.markdown", ], "settings": { "foreground": "#D4D4D4" diff --git a/extensions/theme-defaults/themes/hc_black.json b/extensions/theme-defaults/themes/hc_black.json index 7a257515d8c..b8eda7974b7 100644 --- a/extensions/theme-defaults/themes/hc_black.json +++ b/extensions/theme-defaults/themes/hc_black.json @@ -17,7 +17,8 @@ { "scope": [ "meta.embedded", - "source.groovy.embedded" + "source.groovy.embedded", + "string meta.image.inline.markdown" ], "settings": { "foreground": "#FFFFFF" diff --git a/extensions/theme-defaults/themes/light_vs.json b/extensions/theme-defaults/themes/light_vs.json index ae3ab6645bc..7a80ebf00e0 100644 --- a/extensions/theme-defaults/themes/light_vs.json +++ b/extensions/theme-defaults/themes/light_vs.json @@ -26,13 +26,15 @@ "notebook.selectedCellBackground": "#c8ddf150", "statusBarItem.errorBackground": "#c72e0f", "list.activeSelectionIconForeground": "#FFF", - "list.focusAndSelectionOutline": "#90C2F9" + "list.focusAndSelectionOutline": "#90C2F9", + "terminal.inactiveSelectionBackground": "#E5EBF1", }, "tokenColors": [ { "scope": [ "meta.embedded", - "source.groovy.embedded" + "source.groovy.embedded", + "string meta.image.inline.markdown" ], "settings": { "foreground": "#000000ff" 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 bc56665a86c..76cdb8a9753 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -60,7 +60,11 @@ } }, { - "scope": ["meta.embedded", "source.groovy.embedded"], + "scope": [ + "meta.embedded", + "source.groovy.embedded", + "string meta.image.inline.markdown" + ], "settings": { "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 27b9277f724..ea84bededd5 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -59,7 +59,8 @@ "terminal.ansiBrightBlue": "#819aff", // hue shifted #AE81FF "terminal.ansiBrightMagenta": "#AE81FF", "terminal.ansiBrightCyan": "#66D9EF", - "terminal.ansiBrightWhite": "#f8f8f2" + "terminal.ansiBrightWhite": "#f8f8f2", + "terminal.inactiveSelectionBackground": "#676b7140" }, "tokenColors": [ { diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index 11e7caa3c3e..fccdf7cd600 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -110,7 +110,8 @@ { "scope": [ "meta.embedded", - "source.groovy.embedded" + "source.groovy.embedded", + "string meta.image.inline.markdown" ], "settings": { "foreground": "#F8F8F2" diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 753116e27d1..30615a91f03 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -9,7 +9,8 @@ { "scope": [ "meta.embedded", - "source.groovy.embedded" + "source.groovy.embedded", + "string meta.image.inline.markdown" ], "settings": { "foreground": "#333333" diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index f5bd596d10d..c139400dc56 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -69,7 +69,8 @@ { "scope": [ "meta.embedded", - "source.groovy.embedded" + "source.groovy.embedded", + "string meta.image.inline.markdown" ], "settings": { "foreground": "#F8F8F8" diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js index 66e11c16c5e..c55af7ab7fe 100644 --- a/extensions/theme-seti/build/update-icon-theme.js +++ b/extensions/theme-seti/build/update-icon-theme.js @@ -45,7 +45,8 @@ const nonBuiltInLanguages = { // { fileNames, extensions } const inheritIconFromLanguage = { "jsonc": 'json', "postcss": 'css', - "django-html": 'html' + "django-html": 'html', + "blade": 'php' } const FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo diff --git a/extensions/theme-seti/cgmanifest.json b/extensions/theme-seti/cgmanifest.json index 983ec9c5157..919b27b7c91 100644 --- a/extensions/theme-seti/cgmanifest.json +++ b/extensions/theme-seti/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "seti-ui", "repositoryUrl": "https://github.com/jesseweed/seti-ui", - "commitHash": "4dd6c27e1f5aed8068c2451dbaf0db3364545937" + "commitHash": "2d10473b7575ec00c47eda751ea9caeec6b0b606" } }, "version": "0.1.0" diff --git a/extensions/theme-seti/icons/seti.woff b/extensions/theme-seti/icons/seti.woff index 24cde729664..f0e47486995 100644 Binary files a/extensions/theme-seti/icons/seti.woff and b/extensions/theme-seti/icons/seti.woff differ diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json index 0914afe46c1..abf5c8a0a7e 100644 --- a/extensions/theme-seti/icons/vs-seti-icon-theme.json +++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json @@ -1694,6 +1694,7 @@ "tf": "_terraform", "tf.json": "_terraform", "tfvars": "_terraform", + "tfvars.json": "_terraform", "dtx": "_tex_2", "ins": "_tex_3", "toml": "_config", @@ -1942,7 +1943,8 @@ "vala": "_vala", "vue": "_vue", "postcss": "_css", - "django-html": "_html_3" + "django-html": "_html_3", + "blade": "_php" }, "light": { "file": "_default_light", @@ -2093,6 +2095,7 @@ "tf": "_terraform_light", "tf.json": "_terraform_light", "tfvars": "_terraform_light", + "tfvars.json": "_terraform_light", "dtx": "_tex_2_light", "ins": "_tex_3_light", "toml": "_config_light", @@ -2258,7 +2261,8 @@ "vala": "_vala_light", "vue": "_vue_light", "postcss": "_css_light", - "django-html": "_html_3_light" + "django-html": "_html_3_light", + "blade": "_php_light" }, "fileNames": { "mix": "_hex_light", @@ -2340,5 +2344,5 @@ "npm-debug.log": "_npm_ignored_light" } }, - "version": "https://github.com/jesseweed/seti-ui/commit/4dd6c27e1f5aed8068c2451dbaf0db3364545937" + "version": "https://github.com/jesseweed/seti-ui/commit/2d10473b7575ec00c47eda751ea9caeec6b0b606" } \ No newline at end of file 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 2febfd9bca0..e10c6e67403 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -9,7 +9,8 @@ { "scope": [ "meta.embedded", - "source.groovy.embedded" + "source.groovy.embedded", + "string meta.image.inline.markdown" ], "settings": { "foreground": "#839496" 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 d13c42c0bb2..e5f8e5b5ee5 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -9,7 +9,8 @@ { "scope": [ "meta.embedded", - "source.groovy.embedded" + "source.groovy.embedded", + "string meta.image.inline.markdown" ], "settings": { "foreground": "#657B83" diff --git a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json index b37fd6b0083..eef990db889 100644 --- a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json +++ b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json @@ -15,8 +15,8 @@ "editor.foreground": "#ffffff", "editor.selectionBackground": "#003f8e", "minimap.selectionHighlight": "#003f8e", - "editor.lineHighlightBackground": "#00346e", - "editorLineNumber.activeForeground": "#949494", + "editor.lineHighlightBackground": "#00346e", + "editorLineNumber.activeForeground": "#949494", "editorCursor.foreground": "#ffffff", "editorWhitespace.foreground": "#404f7d", "editorWidget.background": "#001c40", @@ -65,7 +65,12 @@ } }, { - "scope": ["meta.embedded", "source.groovy.embedded", "meta.jsx.children"], + "scope": [ + "meta.embedded", + "source.groovy.embedded", + "meta.jsx.children", + "string meta.image.inline.markdown" + ], "settings": { //"background": "#002451", "foreground": "#FFFFFF" diff --git a/extensions/tsconfig.base.json b/extensions/tsconfig.base.json index 5651d572632..2e4a6009a02 100644 --- a/extensions/tsconfig.base.json +++ b/extensions/tsconfig.base.json @@ -20,7 +20,10 @@ "ES2020.Promise", "ES2020.String", "ES2020.Symbol.WellKnown", - "ES2020.Intl" + "ES2020.Intl", + "ES2021.Promise", + "ES2021.String", + "ES2021.WeakRef" ], "module": "commonjs", "strict": true, diff --git a/extensions/typescript-basics/cgmanifest.json b/extensions/typescript-basics/cgmanifest.json index 7e58e66ed5e..cf253fb2b95 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": "0dfae8cc4807fecfbf8f1add095d9817df824c95" + "commitHash": "73af17bf3e45339df06d92751ab366ce96c38516" } }, "license": "MIT", diff --git a/extensions/typescript-basics/language-configuration.json b/extensions/typescript-basics/language-configuration.json index 07260718b64..739f085339e 100644 --- a/extensions/typescript-basics/language-configuration.json +++ b/extensions/typescript-basics/language-configuration.json @@ -99,6 +99,24 @@ ">" ] ], + "colorizedBracketPairs": [ + [ + "(", + ")" + ], + [ + "[", + "]" + ], + [ + "{", + "}" + ], + [ + "<", + ">" + ] + ], "autoCloseBefore": ";:.,=}])>` \n\t", "folding": { "markers": { diff --git a/extensions/typescript-basics/package.json b/extensions/typescript-basics/package.json index cb6c20d8eed..fef8f0221f0 100644 --- a/extensions/typescript-basics/package.json +++ b/extensions/typescript-basics/package.json @@ -64,6 +64,13 @@ "language": "typescript", "scopeName": "source.ts", "path": "./syntaxes/TypeScript.tmLanguage.json", + "unbalancedBracketScopes": [ + "keyword.operator.relational", + "storage.type.function.arrow", + "keyword.operator.bitwise.shift", + "meta.brace.angle", + "punctuation.definition.tag" + ], "tokenTypes": { "meta.template.expression": "other", "meta.template.expression string": "string", @@ -78,6 +85,12 @@ "language": "typescriptreact", "scopeName": "source.tsx", "path": "./syntaxes/TypeScriptReact.tmLanguage.json", + "unbalancedBracketScopes": [ + "keyword.operator.relational", + "storage.type.function.arrow", + "keyword.operator.bitwise.shift", + "punctuation.definition.tag" + ], "embeddedLanguages": { "meta.tag.tsx": "jsx-tags", "meta.tag.without-attributes.tsx": "jsx-tags", diff --git a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json index 9d97c94fd0d..681581e93d6 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/0dfae8cc4807fecfbf8f1add095d9817df824c95", + "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/73af17bf3e45339df06d92751ab366ce96c38516", "name": "TypeScript", "scopeName": "source.ts", "patterns": [ @@ -3050,7 +3050,7 @@ "name": "keyword.operator.expression.instanceof.ts" } }, - "end": "(?<=\\))|(?=[;),}\\]:?\\-\\+\\>]|\\|\\||\\&\\&|\\!\\=\\=|$|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(===|!==|==|!=)|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" diff --git a/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json index 040013e7dcc..0b1300ecfb9 100644 --- a/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/0dfae8cc4807fecfbf8f1add095d9817df824c95", + "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/73af17bf3e45339df06d92751ab366ce96c38516", "name": "TypeScriptReact", "scopeName": "source.tsx", "patterns": [ @@ -3053,7 +3053,7 @@ "name": "keyword.operator.expression.instanceof.tsx" } }, - "end": "(?<=\\))|(?=[;),}\\]:?\\-\\+\\>]|\\|\\||\\&\\&|\\!\\=\\=|$|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(===|!==|==|!=)|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -5811,10 +5811,6 @@ "name": "punctuation.definition.entity.tsx" } } - }, - { - "name": "invalid.illegal.bad-ampersand.tsx", - "match": "&" } ] }, diff --git a/extensions/typescript-language-features/extension-browser.webpack.config.js b/extensions/typescript-language-features/extension-browser.webpack.config.js index e7ad156bf94..6dbedab0a05 100644 --- a/extensions/typescript-language-features/extension-browser.webpack.config.js +++ b/extensions/typescript-language-features/extension-browser.webpack.config.js @@ -8,6 +8,8 @@ 'use strict'; const CopyPlugin = require('copy-webpack-plugin'); const Terser = require('terser'); +const fs = require('fs'); +const path = require('path'); const defaultConfig = require('../shared.webpack.config'); const withBrowserDefaults = defaultConfig.browser; @@ -35,7 +37,7 @@ module.exports = withBrowserDefaults({ extension: './src/extension.browser.ts', }, plugins: [ - ...browserPlugins, // add plugins, don't replace inherited + ...browserPlugins(__dirname), // add plugins, don't replace inherited // @ts-ignore new CopyPlugin({ @@ -64,9 +66,12 @@ module.exports = withBrowserDefaults({ { from: '../node_modules/typescript/lib/tsserver.js', to: 'typescript/tsserver.web.js', - transform: (content) => { - return Terser.minify(content.toString()).then(output => output.code); + transform: async (content) => { + const dynamicImportCompatPath = path.join(__dirname, '..', 'node_modules', 'typescript', 'lib', 'dynamicImportCompat.js'); + const prefix = fs.existsSync(dynamicImportCompatPath) ? fs.readFileSync(dynamicImportCompatPath) : undefined; + const output = await Terser.minify(content.toString()); + return prefix + '\n' + output.code; }, transformPath: (targetPath) => { return targetPath.replace('tsserver.js', 'tsserver.web.js'); diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index e3b7eadb0c4..15a96456934 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -6,7 +6,7 @@ "author": "vscode", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "enabledApiProposals": [ "resolvers", "workspaceTrust" @@ -34,10 +34,10 @@ "Programming Languages" ], "dependencies": { - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "jsonc-parser": "^2.2.1", "semver": "5.5.1", - "vscode-nls": "^5.0.0", + "vscode-nls": "^5.1.0", "vscode-tas-client": "^0.1.47", "vscode-uri": "^3.0.3" }, diff --git a/extensions/typescript-language-features/src/extension.browser.ts b/extensions/typescript-language-features/src/extension.browser.ts index 6bb57c02dc9..06b650d2375 100644 --- a/extensions/typescript-language-features/src/extension.browser.ts +++ b/extensions/typescript-language-features/src/extension.browser.ts @@ -55,7 +55,7 @@ export function activate( new TypeScriptVersion( TypeScriptVersionSource.Bundled, vscode.Uri.joinPath(context.extensionUri, 'dist/browser/typescript/tsserver.web.js').toString(), - API.fromSimpleString('4.5.4'))); + API.fromSimpleString('4.8.2'))); const lazyClientHost = createLazyClientHost(context, false, { pluginManager, diff --git a/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts index caeb91d1dc3..fd3f84963e6 100644 --- a/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts @@ -190,7 +190,6 @@ export default class FileConfigurationManager extends Disposable { includeCompletionsWithSnippetText: config.get('suggest.includeCompletionsWithSnippetText', true), includeCompletionsWithClassMemberSnippets: config.get('suggest.classMemberSnippets.enabled', true), includeCompletionsWithObjectLiteralMethodSnippets: config.get('suggest.objectLiteralMethodSnippets.enabled', true), - // @ts-expect-error until TS 4.8 autoImportFileExcludePatterns: this.getAutoImportFileExcludePatternsPreference(preferencesConfig, vscode.workspace.getWorkspaceFolder(document.uri)?.uri), useLabelDetailsInCompletionEntries: true, allowIncompleteCompletions: true, diff --git a/extensions/typescript-language-features/src/languageFeatures/hover.ts b/extensions/typescript-language-features/src/languageFeatures/hover.ts index a717e088a3f..362826513bc 100644 --- a/extensions/typescript-language-features/src/languageFeatures/hover.ts +++ b/extensions/typescript-language-features/src/languageFeatures/hover.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; import type * as Proto from '../protocol'; -import { localize } from '../tsServer/versionProvider'; import { ClientCapability, ITypeScriptServiceClient, ServerType } from '../typescriptService'; import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; import { DocumentSelector } from '../utils/documentSelector'; @@ -13,6 +13,8 @@ import { markdownDocumentation } from '../utils/previewer'; import * as typeConverters from '../utils/typeConverters'; import FileConfigurationManager from './fileConfigurationManager'; +const localize = nls.loadMessageBundle(); + class TypeScriptHoverProvider implements vscode.HoverProvider { diff --git a/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts b/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts index 7d2f0288e69..1df1c1e13ed 100644 --- a/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts +++ b/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts @@ -199,7 +199,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable { config.update( updateImportsOnFileMoveName, UpdateImportsOnFileMoveSetting.Always, - vscode.ConfigurationTarget.Global); + this.getConfigTargetScope(config, updateImportsOnFileMoveName)); return true; } case Choice.Never: @@ -208,7 +208,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable { config.update( updateImportsOnFileMoveName, UpdateImportsOnFileMoveSetting.Never, - vscode.ConfigurationTarget.Global); + this.getConfigTargetScope(config, updateImportsOnFileMoveName)); return false; } } @@ -284,6 +284,19 @@ class UpdateImportsOnFileRenameHandler extends Disposable { paths.push(''); return paths.join('\n'); } + + private getConfigTargetScope(config: vscode.WorkspaceConfiguration, settingsName: string): vscode.ConfigurationTarget { + const inspected = config.inspect(settingsName); + if (inspected?.workspaceFolderValue) { + return vscode.ConfigurationTarget.WorkspaceFolder; + } + + if (inspected?.workspaceValue) { + return vscode.ConfigurationTarget.Workspace; + } + + return vscode.ConfigurationTarget.Global; + } } export function register( diff --git a/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts b/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts index ed6af73fcf4..27b41948f75 100644 --- a/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts @@ -11,6 +11,7 @@ import { coalesce } from '../utils/arrays'; import { Delayer, setImmediate } from '../utils/async'; import { nulToken } from '../utils/cancellation'; import { Disposable } from '../utils/dispose'; +import { vscodeNotebookCell } from '../utils/fileSchemes'; import * as languageModeIds from '../utils/languageIds'; import { ResourceMap } from '../utils/resourceMap'; import * as typeConverters from '../utils/typeConverters'; @@ -361,6 +362,98 @@ class GetErrRequest { } } +class TabResourceTracker extends Disposable { + + private readonly _onDidChange = this._register(new vscode.EventEmitter<{ + readonly closed: Iterable; + readonly opened: Iterable; + }>()); + public readonly onDidChange = this._onDidChange.event; + + private readonly _tabResources: ResourceMap<{ readonly tabs: Set }>; + + constructor( + normalizePath: (resource: vscode.Uri) => string | undefined, + config: { + readonly onCaseInsensitiveFileSystem: boolean; + }, + ) { + super(); + + this._tabResources = new ResourceMap<{ readonly tabs: Set }>(normalizePath, config); + + for (const tabGroup of vscode.window.tabGroups.all) { + for (const tab of tabGroup.tabs) { + this.add(tab); + } + } + + this._register(vscode.window.tabGroups.onDidChangeTabs(e => { + const closed = e.closed.flatMap(tab => this.delete(tab)); + const opened = e.opened.flatMap(tab => this.add(tab)); + if (closed.length || opened.length) { + this._onDidChange.fire({ closed, opened }); + } + })); + } + + public has(resource: vscode.Uri): boolean { + if (resource.scheme === vscodeNotebookCell) { + const notebook = vscode.workspace.notebookDocuments.find(doc => + doc.getCells().some(cell => cell.document.uri.toString() === resource.toString())); + + return !!notebook && this.has(notebook.uri); + } + + const entry = this._tabResources.get(resource); + return !!entry && entry.tabs.size > 0; + } + + private add(tab: vscode.Tab): vscode.Uri[] { + const addedResources: vscode.Uri[] = []; + for (const uri of this.getResourcesForTab(tab)) { + const entry = this._tabResources.get(uri); + if (entry) { + entry.tabs.add(tab); + } else { + this._tabResources.set(uri, { tabs: new Set([tab]) }); + addedResources.push(uri); + } + } + return addedResources; + } + + private delete(tab: vscode.Tab): vscode.Uri[] { + const closedResources: vscode.Uri[] = []; + for (const uri of this.getResourcesForTab(tab)) { + const entry = this._tabResources.get(uri); + if (!entry) { + continue; + } + + entry.tabs.delete(tab); + if (entry.tabs.size === 0) { + this._tabResources.delete(uri); + closedResources.push(uri); + } + } + return closedResources; + } + + private getResourcesForTab(tab: vscode.Tab): vscode.Uri[] { + if (tab.input instanceof vscode.TabInputText) { + return [tab.input.uri]; + } else if (tab.input instanceof vscode.TabInputTextDiff) { + return [tab.input.original, tab.input.modified]; + } else if (tab.input instanceof vscode.TabInputNotebook) { + return [tab.input.uri]; + } else { + return []; + } + } +} + + export default class BufferSyncSupport extends Disposable { private readonly client: ITypeScriptServiceClient; @@ -375,6 +468,8 @@ export default class BufferSyncSupport extends Disposable { private listening: boolean = false; private readonly synchronizer: BufferSynchronizer; + private readonly _tabResources: TabResourceTracker; + constructor( client: ITypeScriptServiceClient, modeIds: readonly string[], @@ -391,6 +486,28 @@ export default class BufferSyncSupport extends Disposable { this.pendingDiagnostics = new PendingDiagnostics(pathNormalizer, { onCaseInsensitiveFileSystem }); this.synchronizer = new BufferSynchronizer(client, pathNormalizer, onCaseInsensitiveFileSystem); + this._tabResources = this._register(new TabResourceTracker(pathNormalizer, { onCaseInsensitiveFileSystem })); + this._register(this._tabResources.onDidChange(e => { + if (this.client.configuration.enableProjectDiagnostics) { + return; + } + + for (const closed of e.closed) { + const syncedBuffer = this.syncedBuffers.get(closed); + if (syncedBuffer) { + this.pendingDiagnostics.delete(closed); + this.pendingGetErr?.files.delete(closed); + } + } + + for (const opened of e.opened) { + const syncedBuffer = this.syncedBuffers.get(opened); + if (syncedBuffer) { + this.requestDiagnostic(syncedBuffer); + } + } + })); + this.updateConfiguration(); vscode.workspace.onDidChangeConfiguration(this.updateConfiguration, this, this._disposables); } @@ -494,6 +611,7 @@ export default class BufferSyncSupport extends Disposable { if (!syncedBuffer) { return; } + this.pendingDiagnostics.delete(resource); this.pendingGetErr?.files.delete(resource); this.syncedBuffers.delete(resource); @@ -506,7 +624,7 @@ export default class BufferSyncSupport extends Disposable { public interruptGetErr(f: () => R): R { if (!this.pendingGetErr - || this.client.configuration.enableProjectDiagnostics // `geterr` happens on seperate server so no need to cancel it. + || this.client.configuration.enableProjectDiagnostics // `geterr` happens on separate server so no need to cancel it. ) { return f(); } @@ -628,7 +746,11 @@ export default class BufferSyncSupport extends Disposable { this._validateTypeScript = tsConfig.get('validate.enable', true); } - private shouldValidate(buffer: SyncedBuffer) { + private shouldValidate(buffer: SyncedBuffer): boolean { + if (!this.client.configuration.enableProjectDiagnostics && !this._tabResources.has(buffer.resource)) { // Only validate resources that are showing to the user + return false; + } + switch (buffer.kind) { case BufferKind.JavaScript: return this._validateJavaScript; diff --git a/extensions/typescript-language-features/src/tsServer/versionProvider.electron.ts b/extensions/typescript-language-features/src/tsServer/versionProvider.electron.ts index 6355e5b60c4..ad4f9b9dfe6 100644 --- a/extensions/typescript-language-features/src/tsServer/versionProvider.electron.ts +++ b/extensions/typescript-language-features/src/tsServer/versionProvider.electron.ts @@ -6,10 +6,13 @@ import * as fs from 'fs'; import * as path from 'path'; import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; import API from '../utils/api'; import { TypeScriptServiceConfiguration } from '../utils/configuration'; import { RelativeWorkspacePathResolver } from '../utils/relativePathResolver'; -import { ITypeScriptVersionProvider, localize, TypeScriptVersion, TypeScriptVersionSource } from './versionProvider'; +import { ITypeScriptVersionProvider, TypeScriptVersion, TypeScriptVersionSource } from './versionProvider'; + +const localize = nls.loadMessageBundle(); export class DiskTypeScriptVersionProvider implements ITypeScriptVersionProvider { diff --git a/extensions/typescript-language-features/src/tsServer/versionProvider.ts b/extensions/typescript-language-features/src/tsServer/versionProvider.ts index 43f16c7c19d..89fd07d8c1b 100644 --- a/extensions/typescript-language-features/src/tsServer/versionProvider.ts +++ b/extensions/typescript-language-features/src/tsServer/versionProvider.ts @@ -7,7 +7,7 @@ import * as nls from 'vscode-nls'; import API from '../utils/api'; import { TypeScriptServiceConfiguration } from '../utils/configuration'; -export const localize = nls.loadMessageBundle(); +const localize = nls.loadMessageBundle(); export const enum TypeScriptVersionSource { Bundled = 'bundled', diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 0585285b6d7..a42f5c29f06 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -25,7 +25,7 @@ import * as fileSchemes from './utils/fileSchemes'; import { Logger } from './utils/logger'; import { isWeb } from './utils/platform'; import { TypeScriptPluginPathsProvider } from './utils/pluginPathsProvider'; -import { PluginManager } from './utils/plugins'; +import { PluginManager, TypeScriptServerPlugin } from './utils/plugins'; import { TelemetryProperties, TelemetryReporter, VSCodeTelemetryReporter } from './utils/telemetry'; import Tracer from './utils/tracer'; import { inferredProjectCompilerOptions, ProjectType } from './utils/tsconfig'; @@ -430,32 +430,29 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); handle.onExit((data: TypeScriptServerExitEvent) => { + const { code, signal } = data; + this.error(`TSServer exited. Code: ${code}. Signal: ${signal}`); + + // In practice, the exit code is an integer with no ties to any identity, + // so it can be classified as SystemMetaData, rather than CallstackOrException. + /* __GDPR__ + "tsserver.exitWithCode" : { + "owner": "mjbvz", + "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${include}": [ + "${TypeScriptCommonProperties}" + ] + } + */ + this.logTelemetry('tsserver.exitWithCode', { code: code ?? undefined, signal: signal ?? undefined }); + + if (this.token !== mytoken) { // this is coming from an old process return; } - const { code, signal } = data; - - if (code === null || typeof code === 'undefined') { - this.info(`TSServer exited. Signal: ${signal}`); - } else { - // In practice, the exit code is an integer with no ties to any identity, - // so it can be classified as SystemMetaData, rather than CallstackOrException. - this.error(`TSServer exited with code: ${code}. Signal: ${signal}`); - /* __GDPR__ - "tsserver.exitWithCode" : { - "owner": "mjbvz", - "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "${include}": [ - "${TypeScriptCommonProperties}" - ] - } - */ - this.logTelemetry('tsserver.exitWithCode', { code, signal: signal ?? undefined }); - } - if (handle.tsServerLogFile) { this.info(`TSServer log file: ${handle.tsServerLogFile}`); } @@ -554,8 +551,8 @@ export default class TypeScriptServiceClient extends Disposable implements IType } // Reconfigure any plugins - for (const [config, pluginName] of this.pluginManager.configurations()) { - this.configurePlugin(config, pluginName); + for (const [pluginName, config] of this.pluginManager.configurations()) { + this.configurePlugin(pluginName, config); } } @@ -587,6 +584,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.numberRestarts++; let startService = true; + const pluginExtensionList = this.pluginManager.plugins.map(plugin => plugin.extension.id).join(', '); const reportIssueItem: vscode.MessageItem = { title: localize('serverDiedReportIssue', 'Report Issue'), }; @@ -599,7 +597,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType startService = false; this.hasServerFatallyCrashedTooManyTimes = true; prompt = vscode.window.showErrorMessage( - localize('serverDiedAfterStart', 'The TypeScript language service died 5 times right after it got started. The service will not be restarted.'), + this.pluginManager.plugins.length + ? localize('serverDiedImmediatelyWithPlugins', "The JS/TS language service immediately crashed 5 times. The service will not be restarted.\nThis may be caused by a plugin contributed by one of these extensions: {0}", pluginExtensionList) + : localize('serverDiedImmediately', "The JS/TS language service immediately crashed 5 times. The service will not be restarted."), reportIssueItem); /* __GDPR__ @@ -613,21 +613,30 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.logTelemetry('serviceExited'); } 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.'), - reportIssueItem); + if (!this._isPromptingAfterCrash) { + prompt = vscode.window.showWarningMessage( + this.pluginManager.plugins.length + ? localize('serverDiedFiveTimesWithPlugins', "The JS/TS language service crashed 5 times in the last 5 Minutes.\nThis may be caused by a plugin contributed by one of these extensions: {0}", pluginExtensionList) + : localize('serverDiedFiveTimes', "The JS/TS language service crashed 5 times in the last 5 Minutes."), + reportIssueItem); + } } } else if (['vscode-insiders', 'code-oss'].includes(vscode.env.uriScheme)) { // Prompt after a single restart - if (!this._isPromptingAfterCrash && previousState.type === ServerState.Type.Errored && previousState.error instanceof TypeScriptServerError) { - this.numberRestarts = 0; - this._isPromptingAfterCrash = true; + this.numberRestarts = 0; + if (!this._isPromptingAfterCrash) { prompt = vscode.window.showWarningMessage( - localize('serverDiedOnce', 'The TypeScript language service died unexpectedly.'), + this.pluginManager.plugins.length + ? localize('serverDiedOnceWithPlugins', "The JS/TS language service crashed.\nThis may be caused by a plugin contributed by one of these extensions: {0}", pluginExtensionList) + : localize('serverDiedOnce', "The JS/TS language service crashed."), reportIssueItem); } } + if (prompt) { + this._isPromptingAfterCrash = true; + } + prompt?.then(item => { this._isPromptingAfterCrash = false; @@ -647,7 +656,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } else { const args = previousState.type === ServerState.Type.Errored && previousState.error instanceof TypeScriptServerError - ? getReportIssueArgsForError(previousState.error, previousState.tsServerLogFile) + ? getReportIssueArgsForError(previousState.error, previousState.tsServerLogFile, this.pluginManager.plugins) : undefined; vscode.commands.executeCommand('workbench.action.openIssueReporter', args); } @@ -1005,6 +1014,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType function getReportIssueArgsForError( error: TypeScriptServerError, logPath: string | undefined, + globalPlugins: readonly TypeScriptServerPlugin[], ): { extensionId: string; issueTitle: string; issueBody: string } | undefined { if (!error.serverStack || !error.serverMessage) { return undefined; @@ -1023,6 +1033,10 @@ function getReportIssueArgsForError( 3.`, ]; + if (globalPlugins.length) { + sections.push(`**Global TS Server Plugins**\n\n` + globalPlugins.map(plugin => `- \`${plugin.name}\``).join('\n')); + } + if (logPath) { sections.push(`**TS Server Log** @@ -1036,7 +1050,7 @@ The log file may contain personal data, including full paths and source code fro sections.push(`**TS Server Log** -❗️Server logging disabled. To help us fix crashes like this, please enable logging by setting: +❗️ Server logging disabled. To help us fix crashes like this, please enable logging by setting: \`\`\`json "typescript.tsserver.log": "verbose" diff --git a/extensions/typescript-language-features/src/utils/logLevelMonitor.ts b/extensions/typescript-language-features/src/utils/logLevelMonitor.ts index 0744a64863e..92a48be4cfd 100644 --- a/extensions/typescript-language-features/src/utils/logLevelMonitor.ts +++ b/extensions/typescript-language-features/src/utils/logLevelMonitor.ts @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { localize } from '../tsServer/versionProvider'; +import * as nls from 'vscode-nls'; import { TsServerLogLevel } from './configuration'; import { Disposable } from './dispose'; +const localize = nls.loadMessageBundle(); + export class LogLevelMonitor extends Disposable { private static readonly logLevelConfigKey = 'typescript.tsserver.log'; diff --git a/extensions/typescript-language-features/src/utils/plugins.ts b/extensions/typescript-language-features/src/utils/plugins.ts index 92d61e3e235..697e5422445 100644 --- a/extensions/typescript-language-features/src/utils/plugins.ts +++ b/extensions/typescript-language-features/src/utils/plugins.ts @@ -8,6 +8,7 @@ import * as arrays from './arrays'; import { Disposable } from './dispose'; export interface TypeScriptServerPlugin { + readonly extension: vscode.Extension; readonly uri: vscode.Uri; readonly name: string; readonly enableForWorkspaceTypeScriptVersions: boolean; @@ -74,6 +75,7 @@ export class PluginManager extends Disposable { const plugins: TypeScriptServerPlugin[] = []; for (const plugin of pack.contributes.typescriptServerPlugins) { plugins.push({ + extension, name: plugin.name, enableForWorkspaceTypeScriptVersions: !!plugin.enableForWorkspaceTypeScriptVersions, uri: extension.extensionUri, diff --git a/extensions/typescript-language-features/yarn.lock b/extensions/typescript-language-features/yarn.lock index 9b17075c8c4..81f56c011a9 100644 --- a/extensions/typescript-language-features/yarn.lock +++ b/extensions/typescript-language-features/yarn.lock @@ -2,6 +2,42 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node@16.x": version "16.11.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" @@ -12,10 +48,13 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45" integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" axios@^0.26.1: version "0.26.1" @@ -46,10 +85,10 @@ tas-client@0.1.45: dependencies: axios "^0.26.1" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-tas-client@^0.1.47: version "0.1.47" diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 610dd2590e7..8d4619fa70e 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -33,15 +33,16 @@ "scmActionButton", "scmSelectedProvider", "scmValidation", + "snippetWorkspaceEdit", "taskPresentationGroup", "terminalDataWriteEvent", "terminalDimensions", - "terminalNameChangeEvent", "testCoverage", "testObserver", "textSearchProvider", "timeline", "tokenInformation", + "treeItemCheckbox", "treeViewReveal", "workspaceTrust", "telemetry" 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 874d69541e7..315e94e9be4 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts @@ -11,7 +11,10 @@ import { assertNoRpc, closeAllEditors } from '../utils'; suite('vscode API - commands', () => { - teardown(assertNoRpc); + teardown(async function () { + assertNoRpc(); + await closeAllEditors(); + }); test('getCommands', function (done) { @@ -108,19 +111,24 @@ suite('vscode API - commands', () => { }); test('api-command: vscode.open', async function () { - const uri = Uri.parse(workspace.workspaceFolders![0].uri.toString() + '/far.js'); + assert.ok(workspace.workspaceFolders); + assert.ok(workspace.workspaceFolders.length > 0); + const uri = Uri.parse(workspace.workspaceFolders[0].uri.toString() + '/far.js'); await commands.executeCommand('vscode.open', uri); - assert.strictEqual(window.activeTextEditor?.viewColumn, ViewColumn.One); + assert.strictEqual(window.tabGroups.all.length, 1); assert.strictEqual(window.tabGroups.all[0].activeTab?.group.viewColumn, ViewColumn.One); + assert.strictEqual(window.activeTextEditor?.viewColumn, ViewColumn.One); await commands.executeCommand('vscode.open', uri, ViewColumn.Two); - assert.strictEqual(window.activeTextEditor?.viewColumn, ViewColumn.Two); + assert.strictEqual(window.tabGroups.all.length, 2); assert.strictEqual(window.tabGroups.all[1].activeTab?.group.viewColumn, ViewColumn.Two); + assert.strictEqual(window.activeTextEditor?.viewColumn, ViewColumn.Two); await commands.executeCommand('vscode.open', uri, ViewColumn.One); - assert.strictEqual(window.activeTextEditor?.viewColumn, ViewColumn.One); + assert.strictEqual(window.tabGroups.all.length, 2); assert.strictEqual(window.tabGroups.all[0].activeTab?.group.viewColumn, ViewColumn.One); + assert.strictEqual(window.activeTextEditor?.viewColumn, ViewColumn.One); let e1: Error | undefined = undefined; try { diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/interactiveWindow.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/interactiveWindow.test.ts index 0f85b437235..181068b38f6 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/interactiveWindow.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/interactiveWindow.test.ts @@ -6,22 +6,22 @@ import * as assert from 'assert'; import 'mocha'; import * as vscode from 'vscode'; -import { disposeAll } from '../utils'; -import { Kernel, saveAllFilesAndCloseAll } from './notebook.test'; +import { asPromise, disposeAll } from '../utils'; +import { Kernel, saveAllFilesAndCloseAll } from './notebook.api.test'; export type INativeInteractiveWindow = { notebookUri: vscode.Uri; inputUri: vscode.Uri; notebookEditor: vscode.NotebookEditor }; async function createInteractiveWindow(kernel: Kernel) { - const { notebookEditor } = (await vscode.commands.executeCommand( + const { notebookEditor, inputUri } = (await vscode.commands.executeCommand( 'interactive.open', // Keep focus on the owning file if there is one { viewColumn: vscode.ViewColumn.Beside, preserveFocus: false }, undefined, - kernel.controller.id, + `vscode.vscode-api-tests/${kernel.controller.id}`, undefined )) as unknown as INativeInteractiveWindow; - return notebookEditor; + return { notebookEditor, inputUri }; } async function addCell(code: string, notebook: vscode.NotebookDocument) { @@ -35,7 +35,9 @@ async function addCell(code: string, notebook: vscode.NotebookDocument) { async function addCellAndRun(code: string, notebook: vscode.NotebookDocument, i: number) { const cell = await addCell(code, notebook); + const event = asPromise(vscode.workspace.onDidChangeNotebookDocument); await vscode.commands.executeCommand('notebook.cell.execute', { start: i, end: i + 1 }); + await event; assert.strictEqual(cell.outputs.length, 1, 'execute failed'); return cell; } @@ -45,11 +47,13 @@ async function addCellAndRun(code: string, notebook: vscode.NotebookDocument, i: const testDisposables: vscode.Disposable[] = []; let defaultKernel: Kernel; + let secondKernel: Kernel; setup(async function () { - // there should be ONE default kernel in this suite defaultKernel = new Kernel('mainKernel', 'Notebook Default Kernel', 'interactive'); + secondKernel = new Kernel('secondKernel', 'Notebook Secondary Kernel', 'interactive'); testDisposables.push(defaultKernel.controller); + testDisposables.push(secondKernel.controller); await saveAllFilesAndCloseAll(); }); @@ -59,13 +63,18 @@ async function addCellAndRun(code: string, notebook: vscode.NotebookDocument, i: await saveAllFilesAndCloseAll(); }); - test('Can open an interactive window', async () => { + test('Can open an interactive window and execute from input box', async () => { assert.ok(vscode.workspace.workspaceFolders); - const notebookEditor = await createInteractiveWindow(defaultKernel); + const { notebookEditor, inputUri } = await createInteractiveWindow(defaultKernel); assert.ok(notebookEditor); - // Try adding a cell and running it. - await addCell('print foo', notebookEditor.notebook); + const inputBox = vscode.window.visibleTextEditors.find( + (e) => e.document.uri.path === inputUri.path + ); + await inputBox!.edit((editBuilder) => { + editBuilder.insert(new vscode.Position(0, 0), 'print foo'); + }); + await vscode.commands.executeCommand('interactive.execute', notebookEditor.notebook.uri); assert.strictEqual(notebookEditor.notebook.cellCount, 1); assert.strictEqual(notebookEditor.notebook.cellAt(0).kind, vscode.NotebookCellKind.Code); @@ -73,7 +82,7 @@ async function addCellAndRun(code: string, notebook: vscode.NotebookDocument, i: test('Interactive window scrolls after execute', async () => { assert.ok(vscode.workspace.workspaceFolders); - const notebookEditor = await createInteractiveWindow(defaultKernel); + const { notebookEditor } = await createInteractiveWindow(defaultKernel); assert.ok(notebookEditor); // Run and add a bunch of cells @@ -85,4 +94,22 @@ async function addCellAndRun(code: string, notebook: vscode.NotebookDocument, i: assert.strictEqual(notebookEditor.visibleRanges[notebookEditor.visibleRanges.length - 1].end, notebookEditor.notebook.cellCount, `Last cell is not visible`); }); + + test('Interactive window has the correct kernel', async () => { + assert.ok(vscode.workspace.workspaceFolders); + const { notebookEditor } = await createInteractiveWindow(defaultKernel); + assert.ok(notebookEditor); + + await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + + // Create a new interactive window with a different kernel + const { notebookEditor: notebookEditor2 } = await createInteractiveWindow(secondKernel); + assert.ok(notebookEditor2); + + // Verify the kernel is the secondary one + await addCellAndRun(`print`, notebookEditor2.notebook, 0); + + assert.strictEqual(secondKernel.associatedNotebooks.has(notebookEditor2.notebook.uri.toString()), true, `Secondary kernel was not set as the kernel for the interactive window`); + + }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts new file mode 100644 index 00000000000..7d4d4f9e7ed --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts @@ -0,0 +1,358 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TextDecoder, TextEncoder } from 'util'; +import * as vscode from 'vscode'; +import { asPromise, assertNoRpc, closeAllEditors, createRandomFile, disposeAll, revertAllDirty, saveAllEditors } from '../utils'; + +async function createRandomNotebookFile() { + return createRandomFile('', undefined, '.vsctestnb'); +} + +async function openRandomNotebookDocument() { + const uri = await createRandomNotebookFile(); + return vscode.workspace.openNotebookDocument(uri); +} + +export async function saveAllFilesAndCloseAll() { + await saveAllEditors(); + await closeAllEditors(); +} + + +function sleep(ms: number): Promise { + return new Promise(resolve => { + setTimeout(resolve, ms); + }); +} + +export class Kernel { + + readonly controller: vscode.NotebookController; + + readonly associatedNotebooks = new Set(); + + constructor(id: string, label: string, viewType: string = 'notebookCoreTest') { + this.controller = vscode.notebooks.createNotebookController(id, viewType, label); + this.controller.executeHandler = this._execute.bind(this); + this.controller.supportsExecutionOrder = true; + this.controller.supportedLanguages = ['typescript', 'javascript']; + this.controller.onDidChangeSelectedNotebooks(e => { + if (e.selected) { + this.associatedNotebooks.add(e.notebook.uri.toString()); + } else { + this.associatedNotebooks.delete(e.notebook.uri.toString()); + } + }); + } + + protected async _execute(cells: vscode.NotebookCell[]): Promise { + for (const cell of cells) { + await this._runCell(cell); + } + } + + protected async _runCell(cell: vscode.NotebookCell) { + // create a single output with exec order 1 and output is plain/text + // of either the cell itself or (iff empty) the cell's document's uri + const task = this.controller.createNotebookCellExecution(cell); + task.start(Date.now()); + task.executionOrder = 1; + await sleep(10); // Force to be take some time + await task.replaceOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text(cell.document.getText() || cell.document.uri.toString(), 'text/plain') + ])]); + task.end(true); + } +} + + +function getFocusedCell(editor?: vscode.NotebookEditor) { + return editor ? editor.notebook.cellAt(editor.selections[0].start) : undefined; +} + +const apiTestContentProvider: vscode.NotebookContentProvider = { + openNotebook: async (resource: vscode.Uri): Promise => { + if (/.*empty\-.*\.vsctestnb$/.test(resource.path)) { + return { + metadata: {}, + cells: [] + }; + } + + const dto: vscode.NotebookData = { + metadata: { custom: { testMetadata: false } }, + cells: [ + { + value: 'test', + languageId: 'typescript', + kind: vscode.NotebookCellKind.Code, + outputs: [], + metadata: { custom: { testCellMetadata: 123 } }, + executionSummary: { timing: { startTime: 10, endTime: 20 } } + }, + { + value: 'test2', + languageId: 'typescript', + kind: vscode.NotebookCellKind.Code, + outputs: [ + new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('Hello World', 'text/plain') + ], + { + testOutputMetadata: true, + ['text/plain']: { testOutputItemMetadata: true } + }) + ], + executionSummary: { executionOrder: 5, success: true }, + metadata: { custom: { testCellMetadata: 456 } } + } + ] + }; + return dto; + }, + saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { + return; + }, + saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { + return; + }, + backupNotebook: async (_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) => { + return { + id: '1', + delete: () => { } + }; + } +}; + +(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('Notebook API tests', function () { + + const testDisposables: vscode.Disposable[] = []; + const suiteDisposables: vscode.Disposable[] = []; + + suiteTeardown(async function () { + + assertNoRpc(); + + await revertAllDirty(); + await closeAllEditors(); + + disposeAll(suiteDisposables); + suiteDisposables.length = 0; + }); + + suiteSetup(function () { + suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider)); + }); + + let defaultKernel: Kernel; + + setup(async function () { + // there should be ONE default kernel in this suite + defaultKernel = new Kernel('mainKernel', 'Notebook Default Kernel'); + testDisposables.push(defaultKernel.controller); + await saveAllFilesAndCloseAll(); + }); + + teardown(async function () { + disposeAll(testDisposables); + testDisposables.length = 0; + await saveAllFilesAndCloseAll(); + }); + + test('notebook open', async function () { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test'); + assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript'); + + const secondCell = editor.notebook.cellAt(1); + assert.strictEqual(secondCell.outputs.length, 1); + assert.deepStrictEqual(secondCell.outputs[0].metadata, { testOutputMetadata: true, ['text/plain']: { testOutputItemMetadata: true } }); + assert.strictEqual(secondCell.outputs[0].items.length, 1); + assert.strictEqual(secondCell.outputs[0].items[0].mime, 'text/plain'); + assert.strictEqual(new TextDecoder().decode(secondCell.outputs[0].items[0].data), 'Hello World'); + assert.strictEqual(secondCell.executionSummary?.executionOrder, 5); + assert.strictEqual(secondCell.executionSummary?.success, true); + }); + + test('multiple tabs: different editors with same document', async function () { + const notebook = await openRandomNotebookDocument(); + const firstNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.One }); + const secondNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Beside }); + assert.notStrictEqual(firstNotebookEditor, secondNotebookEditor); + assert.strictEqual(firstNotebookEditor?.notebook, secondNotebookEditor?.notebook, 'split notebook editors share the same document'); + }); + + test('#106657. Opening a notebook from markers view is broken ', async function () { + + const document = await openRandomNotebookDocument(); + const [cell] = document.getCells(); + + assert.strictEqual(vscode.window.activeNotebookEditor, undefined); + + // opening a cell-uri opens a notebook editor + await vscode.window.showTextDocument(cell.document, { viewColumn: vscode.ViewColumn.Active }); + // await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active); + + assert.strictEqual(!!vscode.window.activeNotebookEditor, true); + assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString()); + }); + + test('Cannot open notebook from cell-uri with vscode.open-command', async function () { + + const document = await openRandomNotebookDocument(); + const [cell] = document.getCells(); + + await saveAllFilesAndCloseAll(); + assert.strictEqual(vscode.window.activeNotebookEditor, undefined); + + // BUG is that the editor opener (https://github.com/microsoft/vscode/blob/8e7877bdc442f1e83a7fec51920d82b696139129/src/vs/editor/browser/services/openerService.ts#L69) + // removes the fragment if it matches something numeric. For notebooks that's not wanted... + // opening a cell-uri opens a notebook editor + await vscode.commands.executeCommand('vscode.open', cell.document.uri); + + assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString()); + }); + + test('#97830, #97764. Support switch to other editor types', async function () { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + const edit = new vscode.WorkspaceEdit(); + const focusedCell = getFocusedCell(editor); + assert.ok(focusedCell); + edit.replace(focusedCell.document.uri, focusedCell.document.lineAt(0).range, 'var abc = 0;'); + await vscode.workspace.applyEdit(edit); + + assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'var abc = 0;'); + + // no kernel -> no default language + assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript'); + + await vscode.commands.executeCommand('vscode.openWith', notebook.uri, 'default'); + assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, notebook.uri.path); + }); + + test('#102411 - untitled notebook creation failed', async function () { + await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: 'notebookCoreTest' }); + assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined'); + + await closeAllEditors(); + }); + + test('#115855 onDidSaveNotebookDocument', async function () { + const resource = await createRandomNotebookFile(); + const notebook = await vscode.workspace.openNotebookDocument(resource); + + const notebookEdit = new vscode.NotebookEdit(new vscode.NotebookRange(1, 1), [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, 'test 2', 'javascript')]); + const edit = new vscode.WorkspaceEdit(); + edit.set(notebook.uri, [notebookEdit]); + await vscode.workspace.applyEdit(edit); + assert.strictEqual(notebook.isDirty, true); + + const saveEvent = asPromise(vscode.workspace.onDidSaveNotebookDocument); + await notebook.save(); + await saveEvent; + + assert.strictEqual(notebook.isDirty, false); + }); +}); + +(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('statusbar', () => { + const emitter = new vscode.EventEmitter(); + const onDidCallProvide = emitter.event; + const suiteDisposables: vscode.Disposable[] = []; + suiteTeardown(async function () { + assertNoRpc(); + + await revertAllDirty(); + await closeAllEditors(); + + disposeAll(suiteDisposables); + suiteDisposables.length = 0; + }); + + suiteSetup(() => { + suiteDisposables.push(vscode.notebooks.registerNotebookCellStatusBarItemProvider('notebookCoreTest', { + async provideCellStatusBarItems(cell: vscode.NotebookCell, _token: vscode.CancellationToken): Promise { + emitter.fire(cell); + return []; + } + })); + + suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider)); + }); + + test('provideCellStatusBarItems called on metadata change', async function () { + const provideCalled = asPromise(onDidCallProvide); + const notebook = await openRandomNotebookDocument(); + await vscode.window.showNotebookDocument(notebook); + await provideCalled; + + const edit = new vscode.WorkspaceEdit(); + edit.set(notebook.uri, [vscode.NotebookEdit.updateCellMetadata(0, { inputCollapsed: true })]); + await vscode.workspace.applyEdit(edit); + await provideCalled; + }); +}); + +suite('Notebook & LiveShare', function () { + + const suiteDisposables: vscode.Disposable[] = []; + const notebookType = 'vsls-testing'; + + suiteTeardown(() => { + vscode.Disposable.from(...suiteDisposables).dispose(); + }); + + suiteSetup(function () { + + suiteDisposables.push(vscode.workspace.registerNotebookSerializer(notebookType, new class implements vscode.NotebookSerializer { + deserializeNotebook(content: Uint8Array, _token: vscode.CancellationToken): vscode.NotebookData | Thenable { + const value = new TextDecoder().decode(content); + const cell1 = new vscode.NotebookCellData(vscode.NotebookCellKind.Code, value, 'fooLang'); + cell1.outputs = [new vscode.NotebookCellOutput([vscode.NotebookCellOutputItem.stderr(value)])]; + return new vscode.NotebookData([cell1]); + } + serializeNotebook(data: vscode.NotebookData, _token: vscode.CancellationToken): Uint8Array | Thenable { + return new TextEncoder().encode(data.cells[0].value); + } + }, {}, { + displayName: 'LS', + filenamePattern: ['*'], + })); + }); + + test('command: vscode.resolveNotebookContentProviders', async function () { + + type Info = { viewType: string; displayName: string; filenamePattern: string[] }; + + const info = await vscode.commands.executeCommand('vscode.resolveNotebookContentProviders'); + assert.strictEqual(Array.isArray(info), true); + + const item = info.find(item => item.viewType === notebookType); + assert.ok(item); + assert.strictEqual(item?.viewType, notebookType); + }); + + test('command: vscode.executeDataToNotebook', async function () { + const value = 'dataToNotebook'; + const data = await vscode.commands.executeCommand('vscode.executeDataToNotebook', notebookType, new TextEncoder().encode(value)); + assert.ok(data instanceof vscode.NotebookData); + assert.strictEqual(data.cells.length, 1); + assert.strictEqual(data.cells[0].value, value); + assert.strictEqual(new TextDecoder().decode(data.cells[0].outputs![0].items[0].data), value); + }); + + test('command: vscode.executeNotebookToData', async function () { + const value = 'notebookToData'; + const notebook = new vscode.NotebookData([new vscode.NotebookCellData(vscode.NotebookCellKind.Code, value, 'fooLang')]); + const data = await vscode.commands.executeCommand('vscode.executeNotebookToData', notebookType, notebook); + assert.ok(data instanceof Uint8Array); + assert.deepStrictEqual(new TextDecoder().decode(data), value); + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts index 9fb4248687e..ab11a4ee493 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; import * as utils from '../utils'; -suite.skip('Notebook Document', function () { +suite('Notebook Document', function () { const simpleContentProvider = new class implements vscode.NotebookSerializer { deserializeNotebook(_data: Uint8Array): vscode.NotebookData | Thenable { @@ -173,7 +173,7 @@ suite.skip('Notebook Document', function () { // inserting two new cells { const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 0), [{ + edit.set(document.uri, [vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(0, 0), [{ kind: vscode.NotebookCellKind.Markup, languageId: 'markdown', metadata: undefined, @@ -185,7 +185,7 @@ suite.skip('Notebook Document', function () { metadata: undefined, outputs: [], value: 'new_code' - }]); + }])]); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); @@ -198,8 +198,10 @@ suite.skip('Notebook Document', function () { // deleting cell 1 and 3 { const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 1), []); - edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(2, 3), []); + edit.set(document.uri, [ + vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(0, 1), []), + vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(2, 3), []) + ]); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); } @@ -210,7 +212,7 @@ suite.skip('Notebook Document', function () { // replacing all cells { const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 1), [{ + edit.set(document.uri, [vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(0, 1), [{ kind: vscode.NotebookCellKind.Markup, languageId: 'markdown', metadata: undefined, @@ -222,7 +224,7 @@ suite.skip('Notebook Document', function () { metadata: undefined, outputs: [], value: 'new2_code' - }]); + }])]); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); } @@ -233,7 +235,7 @@ suite.skip('Notebook Document', function () { // remove all cells { const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, document.cellCount), []); + edit.set(document.uri, [vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(0, document.cellCount), [])]); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); } @@ -246,7 +248,7 @@ suite.skip('Notebook Document', function () { assert.strictEqual(document.cellCount, 1); const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 0), [{ + edit.set(document.uri, [vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(0, 0), [{ kind: vscode.NotebookCellKind.Markup, languageId: 'markdown', metadata: undefined, @@ -258,7 +260,7 @@ suite.skip('Notebook Document', function () { metadata: undefined, outputs: [], value: 'new_code' - }]); + }])]); const event = utils.asPromise(vscode.workspace.onDidChangeNotebookDocument); @@ -287,7 +289,7 @@ suite.skip('Notebook Document', function () { const document = await vscode.workspace.openNotebookDocument(uri); const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCellMetadata(document.uri, 0, { inputCollapsed: true }); + edit.set(document.uri, [vscode.NotebookEdit.updateCellMetadata(0, { inputCollapsed: true })]); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); assert.strictEqual(document.cellAt(0).metadata.inputCollapsed, true); @@ -300,7 +302,7 @@ suite.skip('Notebook Document', function () { const edit = new vscode.WorkspaceEdit(); const event = utils.asPromise(vscode.workspace.onDidChangeNotebookDocument); - edit.replaceNotebookCellMetadata(document.uri, 0, { inputCollapsed: true }); + edit.set(document.uri, [vscode.NotebookEdit.updateCellMetadata(0, { inputCollapsed: true })]); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); const data = await event; @@ -315,6 +317,18 @@ suite.skip('Notebook Document', function () { assert.strictEqual(data.cellChanges[0].cell.index, 0); }); + test('workspace edit API (notebookMetadata)', async function () { + const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); + const document = await vscode.workspace.openNotebookDocument(uri); + + const edit = new vscode.WorkspaceEdit(); + const metdataEdit = vscode.NotebookEdit.updateNotebookMetadata({ ...document.metadata, custom: { ...(document.metadata.custom || {}), extraNotebookMetadata: true } }); + edit.set(document.uri, [metdataEdit]); + const success = await vscode.workspace.applyEdit(edit); + assert.equal(success, true); + assert.ok(document.metadata.custom.extraNotebookMetadata, `Test metadata not found`); + }); + test('document save API', async function () { const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); const notebook = await vscode.workspace.openNotebookDocument(uri); @@ -326,7 +340,7 @@ suite.skip('Notebook Document', function () { assert.strictEqual(notebook.notebookType, 'notebook.nbdtest'); const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(notebook.uri, new vscode.NotebookRange(0, 0), [{ + edit.set(notebook.uri, [vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(0, 0), [{ kind: vscode.NotebookCellKind.Markup, languageId: 'markdown', metadata: undefined, @@ -338,7 +352,7 @@ suite.skip('Notebook Document', function () { metadata: undefined, outputs: [], value: 'new_code' - }]); + }])]); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); @@ -387,7 +401,7 @@ suite.skip('Notebook Document', function () { assert.strictEqual(document.isDirty, false); const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, document.cellCount), []); + edit.set(document.uri, [vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(0, document.cellCount), [])]); assert.ok(await vscode.workspace.applyEdit(edit)); assert.strictEqual(document.isDirty, true); @@ -402,7 +416,7 @@ suite.skip('Notebook Document', function () { assert.strictEqual(document.isDirty, false); const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, document.cellCount), []); + edit.set(document.uri, [vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(0, document.cellCount), [])]); assert.ok(await vscode.workspace.applyEdit(edit)); assert.strictEqual(document.isDirty, true); @@ -411,7 +425,7 @@ suite.skip('Notebook Document', function () { assert.strictEqual(document.isDirty, false); }); - test('onDidOpenNotebookDocument - emit event only once when opened in two editors', async function () { + test.skip('onDidOpenNotebookDocument - emit event only once when opened in two editors', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/157222 const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); let counter = 0; testDisposables.push(vscode.workspace.onDidOpenNotebookDocument(nb => { diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts index 12b79163769..e14c48fdd17 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts @@ -65,39 +65,6 @@ import * as utils from '../utils'; testDisposables.length = 0; }); - test.skip('showNotebookDocument', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/139078 - - const notebookDocumentsFromOnDidOpen = new Set(); - const sub = vscode.workspace.onDidOpenNotebookDocument(e => { - notebookDocumentsFromOnDidOpen.add(e); - }); - - const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - - const editor = await vscode.window.showNotebookDocument(uri); - assert.strictEqual(uri.toString(), editor.notebook.uri.toString()); - - assert.strictEqual(notebookDocumentsFromOnDidOpen.has(editor.notebook), true); - - const includes = vscode.workspace.notebookDocuments.includes(editor.notebook); - assert.strictEqual(true, includes); - - sub.dispose(); - }); - - // TODO@rebornix deal with getting started - test.skip('notebook editor has viewColumn', async function () { - - const uri1 = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const editor1 = await vscode.window.showNotebookDocument(uri1); - - assert.strictEqual(editor1.viewColumn, vscode.ViewColumn.One); - - const uri2 = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const editor2 = await vscode.window.showNotebookDocument(uri2, { viewColumn: vscode.ViewColumn.Beside }); - assert.strictEqual(editor2.viewColumn, vscode.ViewColumn.Two); - }); - // #138683 test('Opening a notebook should fire activeNotebook event changed only once', async function () { const openedEditor = onDidOpenNotebookEditor(); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.kernel.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.kernel.test.ts new file mode 100644 index 00000000000..0c4cff5cf4b --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.kernel.test.ts @@ -0,0 +1,494 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TextDecoder } from 'util'; +import * as vscode from 'vscode'; +import { asPromise, assertNoRpc, closeAllEditors, createRandomFile, DeferredPromise, disposeAll, revertAllDirty, saveAllEditors } from '../utils'; + +async function createRandomNotebookFile() { + return createRandomFile('', undefined, '.vsctestnb'); +} + +async function openRandomNotebookDocument() { + const uri = await createRandomNotebookFile(); + return vscode.workspace.openNotebookDocument(uri); +} + +export async function saveAllFilesAndCloseAll() { + await saveAllEditors(); + await closeAllEditors(); +} + +async function withEvent(event: vscode.Event, callback: (e: Promise) => Promise) { + const e = asPromise(event); + await callback(e); +} + + +function sleep(ms: number): Promise { + return new Promise(resolve => { + setTimeout(resolve, ms); + }); +} + +export class Kernel { + + readonly controller: vscode.NotebookController; + + readonly associatedNotebooks = new Set(); + + constructor(id: string, label: string, viewType: string = 'notebookCoreTest') { + this.controller = vscode.notebooks.createNotebookController(id, viewType, label); + this.controller.executeHandler = this._execute.bind(this); + this.controller.supportsExecutionOrder = true; + this.controller.supportedLanguages = ['typescript', 'javascript']; + this.controller.onDidChangeSelectedNotebooks(e => { + if (e.selected) { + this.associatedNotebooks.add(e.notebook.uri.toString()); + } else { + this.associatedNotebooks.delete(e.notebook.uri.toString()); + } + }); + } + + protected async _execute(cells: vscode.NotebookCell[]): Promise { + for (const cell of cells) { + await this._runCell(cell); + } + } + + protected async _runCell(cell: vscode.NotebookCell) { + // create a single output with exec order 1 and output is plain/text + // of either the cell itself or (iff empty) the cell's document's uri + const task = this.controller.createNotebookCellExecution(cell); + task.start(Date.now()); + task.executionOrder = 1; + await sleep(10); // Force to be take some time + await task.replaceOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text(cell.document.getText() || cell.document.uri.toString(), 'text/plain') + ])]); + task.end(true); + } +} + + +async function assertKernel(kernel: Kernel, notebook: vscode.NotebookDocument): Promise { + const success = await vscode.commands.executeCommand('notebook.selectKernel', { + extension: 'vscode.vscode-api-tests', + id: kernel.controller.id + }); + assert.ok(success, `expected selected kernel to be ${kernel.controller.id}`); + assert.ok(kernel.associatedNotebooks.has(notebook.uri.toString())); +} + +const apiTestContentProvider: vscode.NotebookContentProvider = { + openNotebook: async (resource: vscode.Uri): Promise => { + if (/.*empty\-.*\.vsctestnb$/.test(resource.path)) { + return { + metadata: {}, + cells: [] + }; + } + + const dto: vscode.NotebookData = { + metadata: { custom: { testMetadata: false } }, + cells: [ + { + value: 'test', + languageId: 'typescript', + kind: vscode.NotebookCellKind.Code, + outputs: [], + metadata: { custom: { testCellMetadata: 123 } }, + executionSummary: { timing: { startTime: 10, endTime: 20 } } + }, + { + value: 'test2', + languageId: 'typescript', + kind: vscode.NotebookCellKind.Code, + outputs: [ + new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('Hello World', 'text/plain') + ], + { + testOutputMetadata: true, + ['text/plain']: { testOutputItemMetadata: true } + }) + ], + executionSummary: { executionOrder: 5, success: true }, + metadata: { custom: { testCellMetadata: 456 } } + } + ] + }; + return dto; + }, + saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { + return; + }, + saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { + return; + }, + backupNotebook: async (_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) => { + return { + id: '1', + delete: () => { } + }; + } +}; + +(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('Notebook Kernel API tests', function () { + + const testDisposables: vscode.Disposable[] = []; + const suiteDisposables: vscode.Disposable[] = []; + + suiteTeardown(async function () { + + assertNoRpc(); + + await revertAllDirty(); + await closeAllEditors(); + + disposeAll(suiteDisposables); + suiteDisposables.length = 0; + }); + + suiteSetup(function () { + suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider)); + }); + + let defaultKernel: Kernel; + + setup(async function () { + // there should be ONE default kernel in this suite + defaultKernel = new Kernel('mainKernel', 'Notebook Default Kernel'); + testDisposables.push(defaultKernel.controller); + await saveAllFilesAndCloseAll(); + }); + + teardown(async function () { + disposeAll(testDisposables); + testDisposables.length = 0; + await saveAllFilesAndCloseAll(); + }); + + test('cell execute command takes arguments', async () => { + const notebook = await openRandomNotebookDocument(); + await vscode.window.showNotebookDocument(notebook); + assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); + const editor = vscode.window.activeNotebookEditor!; + const cell = editor.notebook.cellAt(0); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async event => { + await vscode.commands.executeCommand('notebook.execute'); + await event; + assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked + }); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async event => { + await vscode.commands.executeCommand('notebook.cell.clearOutputs'); + await event; + assert.strictEqual(cell.outputs.length, 0, 'should clear'); + }); + + const secondResource = await createRandomNotebookFile(); + await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async event => { + await vscode.commands.executeCommand('notebook.cell.execute', { start: 0, end: 1 }, notebook.uri); + await event; + assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked + assert.strictEqual(vscode.window.activeNotebookEditor?.notebook.uri.fsPath, secondResource.fsPath); + }); + }); + + test('cell execute command takes arguments 2', async () => { + const notebook = await openRandomNotebookDocument(); + await vscode.window.showNotebookDocument(notebook); + + let firstCellExecuted = false; + let secondCellExecuted = false; + + const def = new DeferredPromise(); + testDisposables.push(vscode.workspace.onDidChangeNotebookDocument(e => { + e.cellChanges.forEach(change => { + if (change.cell.index === 0 && change.executionSummary) { + firstCellExecuted = true; + } + + if (change.cell.index === 1 && change.executionSummary) { + secondCellExecuted = true; + } + }); + + if (firstCellExecuted && secondCellExecuted) { + def.complete(); + } + })); + + vscode.commands.executeCommand('notebook.cell.execute', { document: notebook.uri, ranges: [{ start: 0, end: 1 }, { start: 1, end: 2 }] }); + + await def.p; + await saveAllFilesAndCloseAll(); + }); + + test('document execute command takes arguments', async () => { + const notebook = await openRandomNotebookDocument(); + await vscode.window.showNotebookDocument(notebook); + assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); + const editor = vscode.window.activeNotebookEditor!; + const cell = editor.notebook.cellAt(0); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await vscode.commands.executeCommand('notebook.execute', notebook.uri); + await event; + assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked + }); + }); + + test('cell execute and select kernel', async function () { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first'); + + const cell = editor.notebook.cellAt(0); + + const alternativeKernel = new class extends Kernel { + constructor() { + super('secondaryKernel', 'Notebook Secondary Test Kernel'); + this.controller.supportsExecutionOrder = false; + } + + override async _runCell(cell: vscode.NotebookCell) { + const task = this.controller.createNotebookCellExecution(cell); + task.start(); + await task.replaceOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my second output', 'text/plain') + ])]); + task.end(true); + } + }; + testDisposables.push(alternativeKernel.controller); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await assertKernel(defaultKernel, notebook); + await vscode.commands.executeCommand('notebook.cell.execute'); + await event; + assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked + assert.strictEqual(cell.outputs[0].items.length, 1); + assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain'); + assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), cell.document.getText()); + }); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await assertKernel(alternativeKernel, notebook); + await vscode.commands.executeCommand('notebook.cell.execute'); + await event; + assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked + assert.strictEqual(cell.outputs[0].items.length, 1); + assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain'); + assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), 'my second output'); + }); + }); + + test('onDidChangeCellExecutionState is fired', async () => { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + const cell = editor.notebook.cellAt(0); + + let eventCount = 0; + const def = new DeferredPromise(); + testDisposables.push(vscode.notebooks.onDidChangeNotebookCellExecutionState(e => { + try { + assert.strictEqual(e.cell.document.uri.toString(), cell.document.uri.toString(), 'event should be fired for the executing cell'); + + if (eventCount === 0) { + assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Pending, 'should be set to Pending'); + } else if (eventCount === 1) { + assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Executing, 'should be set to Executing'); + assert.strictEqual(cell.outputs.length, 0, 'no outputs yet: ' + JSON.stringify(cell.outputs[0])); + } else if (e.state === vscode.NotebookCellExecutionState.Idle) { + assert.strictEqual(cell.outputs.length, 1, 'should have an output'); + def.complete(); + } + + eventCount++; + } catch (err) { + def.error(err); + } + })); + + vscode.commands.executeCommand('notebook.cell.execute', { document: notebook.uri, ranges: [{ start: 0, end: 1 }] }); + + await def.p; + }); + + test('Output changes are applied once the promise resolves', async function () { + + let called = false; + + const verifyOutputSyncKernel = new class extends Kernel { + + constructor() { + super('verifyOutputSyncKernel', ''); + } + + override async _execute(cells: vscode.NotebookCell[]) { + const [cell] = cells; + const task = this.controller.createNotebookCellExecution(cell); + task.start(); + await task.replaceOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('Some output', 'text/plain') + ])]); + assert.strictEqual(cell.notebook.cellAt(0).outputs.length, 1); + assert.deepStrictEqual(new TextDecoder().decode(cell.notebook.cellAt(0).outputs[0].items[0].data), 'Some output'); + task.end(undefined); + called = true; + } + }; + + const notebook = await openRandomNotebookDocument(); + await vscode.window.showNotebookDocument(notebook); + await assertKernel(verifyOutputSyncKernel, notebook); + await vscode.commands.executeCommand('notebook.cell.execute'); + assert.strictEqual(called, true); + verifyOutputSyncKernel.controller.dispose(); + }); + + test('executionSummary', async () => { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + const cell = editor.notebook.cellAt(0); + + assert.strictEqual(cell.executionSummary?.success, undefined); + assert.strictEqual(cell.executionSummary?.executionOrder, undefined); + await vscode.commands.executeCommand('notebook.cell.execute'); + assert.strictEqual(cell.outputs.length, 1, 'should execute'); + assert.ok(cell.executionSummary); + assert.strictEqual(cell.executionSummary!.success, true); + assert.strictEqual(typeof cell.executionSummary!.executionOrder, 'number'); + }); + + test('initialize executionSummary', async () => { + + const document = await openRandomNotebookDocument(); + const cell = document.cellAt(0); + + assert.strictEqual(cell.executionSummary?.success, undefined); + assert.strictEqual(cell.executionSummary?.timing?.startTime, 10); + assert.strictEqual(cell.executionSummary?.timing?.endTime, 20); + + }); + + test('execution cancelled when delete while executing', async () => { + const document = await openRandomNotebookDocument(); + const cell = document.cellAt(0); + + let executionWasCancelled = false; + const cancelledKernel = new class extends Kernel { + constructor() { + super('cancelledKernel', ''); + } + + override async _execute(cells: vscode.NotebookCell[]) { + const [cell] = cells; + const exe = this.controller.createNotebookCellExecution(cell); + exe.token.onCancellationRequested(() => executionWasCancelled = true); + } + }; + testDisposables.push(cancelledKernel.controller); + + await vscode.window.showNotebookDocument(document); + await assertKernel(cancelledKernel, document); + await vscode.commands.executeCommand('notebook.cell.execute'); + + // Delete executing cell + const edit = new vscode.WorkspaceEdit(); + edit.set(cell!.notebook.uri, [vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(cell!.index, cell!.index + 1), [])]); + await vscode.workspace.applyEdit(edit); + + assert.strictEqual(executionWasCancelled, true); + }); + + test('appendOutput to different cell', async function () { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + const cell0 = editor.notebook.cellAt(0); + const notebookEdit = new vscode.NotebookEdit(new vscode.NotebookRange(1, 1), [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, 'test 2', 'javascript')]); + const edit = new vscode.WorkspaceEdit(); + edit.set(notebook.uri, [notebookEdit]); + await vscode.workspace.applyEdit(edit); + const cell1 = editor.notebook.cellAt(1); + + const nextCellKernel = new class extends Kernel { + constructor() { + super('nextCellKernel', 'Append to cell kernel'); + } + + override async _runCell(cell: vscode.NotebookCell) { + const task = this.controller.createNotebookCellExecution(cell); + task.start(); + await task.appendOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my output') + ])], cell1); + await task.appendOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my output 2') + ])], cell1); + task.end(true); + } + }; + testDisposables.push(nextCellKernel.controller); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await assertKernel(nextCellKernel, notebook); + await vscode.commands.executeCommand('notebook.cell.execute'); + await event; + assert.strictEqual(cell0.outputs.length, 0, 'should not change cell 0'); + assert.strictEqual(cell1.outputs.length, 2, 'should update cell 1'); + assert.strictEqual(cell1.outputs[0].items.length, 1); + assert.deepStrictEqual(new TextDecoder().decode(cell1.outputs[0].items[0].data), 'my output'); + }); + }); + + test('replaceOutput to different cell', async function () { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + const cell0 = editor.notebook.cellAt(0); + const notebookEdit = new vscode.NotebookEdit(new vscode.NotebookRange(1, 1), [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, 'test 2', 'javascript')]); + const edit = new vscode.WorkspaceEdit(); + edit.set(notebook.uri, [notebookEdit]); + await vscode.workspace.applyEdit(edit); + const cell1 = editor.notebook.cellAt(1); + + const nextCellKernel = new class extends Kernel { + constructor() { + super('nextCellKernel', 'Replace to cell kernel'); + } + + override async _runCell(cell: vscode.NotebookCell) { + const task = this.controller.createNotebookCellExecution(cell); + task.start(); + await task.replaceOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my output') + ])], cell1); + await task.replaceOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my output 2') + ])], cell1); + task.end(true); + } + }; + testDisposables.push(nextCellKernel.controller); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await assertKernel(nextCellKernel, notebook); + await vscode.commands.executeCommand('notebook.cell.execute'); + await event; + assert.strictEqual(cell0.outputs.length, 0, 'should not change cell 0'); + assert.strictEqual(cell1.outputs.length, 1, 'should update cell 1'); + assert.strictEqual(cell1.outputs[0].items.length, 1); + assert.deepStrictEqual(new TextDecoder().decode(cell1.outputs[0].items[0].data), 'my output 2'); + }); + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts deleted file mode 100644 index 88eb9d8a2bb..00000000000 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ /dev/null @@ -1,1137 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import { TextDecoder, TextEncoder } from 'util'; -import * as vscode from 'vscode'; -import { asPromise, assertNoRpc, closeAllEditors, createRandomFile, disposeAll, revertAllDirty, saveAllEditors } from '../utils'; - -async function createRandomNotebookFile() { - return createRandomFile('', undefined, '.vsctestnb'); -} - -async function openRandomNotebookDocument() { - const uri = await createRandomNotebookFile(); - return vscode.workspace.openNotebookDocument(uri); -} - -export async function saveAllFilesAndCloseAll() { - await saveAllEditors(); - await closeAllEditors(); -} - -async function withEvent(event: vscode.Event, callback: (e: Promise) => Promise) { - const e = asPromise(event); - await callback(e); -} - - -function sleep(ms: number): Promise { - return new Promise(resolve => { - setTimeout(resolve, ms); - }); -} - -export class Kernel { - - readonly controller: vscode.NotebookController; - - readonly associatedNotebooks = new Set(); - - constructor(id: string, label: string, viewType: string = 'notebookCoreTest') { - this.controller = vscode.notebooks.createNotebookController(id, viewType, label); - this.controller.executeHandler = this._execute.bind(this); - this.controller.supportsExecutionOrder = true; - this.controller.supportedLanguages = ['typescript', 'javascript']; - this.controller.onDidChangeSelectedNotebooks(e => { - if (e.selected) { - this.associatedNotebooks.add(e.notebook.uri.toString()); - } else { - this.associatedNotebooks.delete(e.notebook.uri.toString()); - } - }); - } - - protected async _execute(cells: vscode.NotebookCell[]): Promise { - for (const cell of cells) { - await this._runCell(cell); - } - } - - protected async _runCell(cell: vscode.NotebookCell) { - // create a single output with exec order 1 and output is plain/text - // of either the cell itself or (iff empty) the cell's document's uri - const task = this.controller.createNotebookCellExecution(cell); - task.start(Date.now()); - task.executionOrder = 1; - await sleep(10); // Force to be take some time - await task.replaceOutput([new vscode.NotebookCellOutput([ - vscode.NotebookCellOutputItem.text(cell.document.getText() || cell.document.uri.toString(), 'text/plain') - ])]); - task.end(true); - } -} - - -function getFocusedCell(editor?: vscode.NotebookEditor) { - return editor ? editor.notebook.cellAt(editor.selections[0].start) : undefined; -} - -async function assertKernel(kernel: Kernel, notebook: vscode.NotebookDocument): Promise { - const success = await vscode.commands.executeCommand('notebook.selectKernel', { - extension: 'vscode.vscode-api-tests', - id: kernel.controller.id - }); - assert.ok(success, `expected selected kernel to be ${kernel.controller.id}`); - assert.ok(kernel.associatedNotebooks.has(notebook.uri.toString())); -} - -const apiTestContentProvider: vscode.NotebookContentProvider = { - openNotebook: async (resource: vscode.Uri): Promise => { - if (/.*empty\-.*\.vsctestnb$/.test(resource.path)) { - return { - metadata: {}, - cells: [] - }; - } - - const dto: vscode.NotebookData = { - metadata: { custom: { testMetadata: false } }, - cells: [ - { - value: 'test', - languageId: 'typescript', - kind: vscode.NotebookCellKind.Code, - outputs: [], - metadata: { custom: { testCellMetadata: 123 } }, - executionSummary: { timing: { startTime: 10, endTime: 20 } } - }, - { - value: 'test2', - languageId: 'typescript', - kind: vscode.NotebookCellKind.Code, - outputs: [ - new vscode.NotebookCellOutput([ - vscode.NotebookCellOutputItem.text('Hello World', 'text/plain') - ], - { - testOutputMetadata: true, - ['text/plain']: { testOutputItemMetadata: true } - }) - ], - executionSummary: { executionOrder: 5, success: true }, - metadata: { custom: { testCellMetadata: 456 } } - } - ] - }; - return dto; - }, - saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { - return; - }, - saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { - return; - }, - backupNotebook: async (_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) => { - return { - id: '1', - delete: () => { } - }; - } -}; - -(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('Notebook API tests', function () { - - const testDisposables: vscode.Disposable[] = []; - const suiteDisposables: vscode.Disposable[] = []; - - suiteTeardown(async function () { - - assertNoRpc(); - - await revertAllDirty(); - await closeAllEditors(); - - disposeAll(suiteDisposables); - suiteDisposables.length = 0; - }); - - suiteSetup(function () { - suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider)); - }); - - let defaultKernel: Kernel; - - setup(async function () { - // there should be ONE default kernel in this suite - defaultKernel = new Kernel('mainKernel', 'Notebook Default Kernel'); - testDisposables.push(defaultKernel.controller); - await saveAllFilesAndCloseAll(); - }); - - teardown(async function () { - disposeAll(testDisposables); - testDisposables.length = 0; - await saveAllFilesAndCloseAll(); - }); - - test.skip('correct cell selection on undo/redo of cell creation', async function () { - const notebook = await openRandomNotebookDocument(); - await vscode.window.showNotebookDocument(notebook); - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - await vscode.commands.executeCommand('undo'); - const selectionUndo = [...vscode.window.activeNotebookEditor!.selections]; - await vscode.commands.executeCommand('redo'); - const selectionRedo = vscode.window.activeNotebookEditor!.selections; - - // On undo, the selected cell must be the upper cell, ie the first one - assert.strictEqual(selectionUndo.length, 1); - assert.strictEqual(selectionUndo[0].start, 0); - assert.strictEqual(selectionUndo[0].end, 1); - // On redo, the selected cell must be the new cell, ie the second one - assert.strictEqual(selectionRedo.length, 1); - assert.strictEqual(selectionRedo[0].start, 1); - assert.strictEqual(selectionRedo[0].end, 2); - }); - - test.skip('editor editing event', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/152145 - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - - const cellsChangeEvent = asPromise(vscode.workspace.onDidChangeNotebookDocument); - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - const cellChangeEventRet = await cellsChangeEvent; - assert.strictEqual(cellChangeEventRet.notebook, editor.notebook); - assert.strictEqual(cellChangeEventRet.contentChanges.length, 1); - assert.deepStrictEqual(cellChangeEventRet.contentChanges[0], { - range: new vscode.NotebookRange(1, 1), - removedCells: [], - addedCells: [editor.notebook.cellAt(1)] - }); - - const moveCellEvent = asPromise(vscode.workspace.onDidChangeNotebookDocument); - await vscode.commands.executeCommand('notebook.cell.moveUp'); - await moveCellEvent; - - const cellOutputChange = asPromise(vscode.workspace.onDidChangeNotebookDocument); - await vscode.commands.executeCommand('notebook.cell.execute'); - const cellOutputsAddedRet = await cellOutputChange; - - assert.strictEqual(cellOutputsAddedRet.notebook.uri.toString(), editor.notebook.uri.toString()); - assert.strictEqual(cellOutputsAddedRet.metadata, undefined); - assert.strictEqual(cellOutputsAddedRet.contentChanges.length, 0); - assert.strictEqual(cellOutputsAddedRet.cellChanges.length, 1); - assert.deepStrictEqual(cellOutputsAddedRet.cellChanges[0].cell, editor.notebook.cellAt(0)); - assert.deepStrictEqual(cellOutputsAddedRet.cellChanges[0].executionSummary, { executionOrder: undefined, success: undefined, timing: undefined }); // TODO@jrieken should this be undefined instead all empty? - assert.strictEqual(cellOutputsAddedRet.cellChanges[0].document, undefined); - assert.strictEqual(cellOutputsAddedRet.cellChanges[0].metadata, undefined); - assert.strictEqual(cellOutputsAddedRet.cellChanges[0].outputs, undefined); - assert.strictEqual(cellOutputsAddedRet.cellChanges[0].cell.outputs.length, 1); - - const cellOutputClear = asPromise(vscode.workspace.onDidChangeNotebookDocument); - await vscode.commands.executeCommand('notebook.cell.clearOutputs'); - const cellOutputsCleardRet = await cellOutputClear; - assert.deepStrictEqual(cellOutputsCleardRet, { - notebook: editor.notebook, - metadata: undefined, - contentChanges: [], - cellChanges: [{ - cell: editor.notebook.cellAt(0), - document: undefined, - executionSummary: undefined, - metadata: undefined, - outputs: editor.notebook.cellAt(0).outputs - }], - }); - assert.strictEqual(cellOutputsCleardRet.cellChanges[0].cell.outputs.length, 0); - - // const cellChangeLanguage = getEventOncePromise(vscode.notebooks.onDidChangeCellLanguage); - // await vscode.commands.executeCommand('notebook.cell.changeToMarkdown'); - // const cellChangeLanguageRet = await cellChangeLanguage; - // assert.deepStrictEqual(cellChangeLanguageRet, { - // document: vscode.window.activeNotebookEditor!.document, - // cells: vscode.window.activeNotebookEditor!.document.cellAt(0), - // language: 'markdown' - // }); - }); - - test('edit API batch edits', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - - const notebookChangeEvent = asPromise(vscode.workspace.onDidChangeNotebookDocument); - const version = editor.notebook.version; - const edit = new vscode.WorkspaceEdit(); - const cellEdit = vscode.NotebookEdit.replaceCells(new vscode.NotebookRange(1, 0), [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]); - const metdataEdit = vscode.NotebookEdit.updateNotebookMetadata({ ...notebook.metadata, custom: { ...(notebook.metadata.custom || {}), extraNotebookMetadata: true } }); - edit.set(notebook.uri, [cellEdit, metdataEdit]); - await vscode.workspace.applyEdit(edit); - await notebookChangeEvent; - - const notebookChangeEvent2 = asPromise(vscode.workspace.onDidChangeNotebookDocument); - const edit2 = new vscode.WorkspaceEdit(); - const cellMetadataEdit = vscode.NotebookEdit.updateCellMetadata(0, { extraCellMetadata: true }); - edit2.set(notebook.uri, [cellMetadataEdit]); - await vscode.workspace.applyEdit(edit2); - await notebookChangeEvent2; - - assert.strictEqual(version + 2, editor.notebook.version); - const cell = editor.notebook.cellAt(0); - assert.ok(editor.notebook.metadata.custom.extraNotebookMetadata, `Test metadata not found`); - assert.ok(cell.metadata.extraCellMetadata, `Test cell metdata not found`); - }); - - test('edit API batch edits undo/redo', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - - const notebookChangeEvent = asPromise(vscode.workspace.onDidChangeNotebookDocument); - const version = editor.notebook.version; - await editor.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]); - editBuilder.replaceCellMetadata(0, { inputCollapsed: false }); - }); - - await notebookChangeEvent; - assert.strictEqual(editor.notebook.cellCount, 3); - assert.strictEqual(editor.notebook.cellAt(0)?.metadata.inputCollapsed, false); - assert.strictEqual(version + 1, editor.notebook.version); - - await vscode.commands.executeCommand('undo'); - assert.strictEqual(version + 2, editor.notebook.version); - assert.strictEqual(editor.notebook.cellAt(0)?.metadata.inputCollapsed, undefined); - assert.strictEqual(editor.notebook.cellCount, 2); - }); - - // #126371 - test.skip('#98841, initialzation should not emit cell change events.', async function () { - let count = 0; - - testDisposables.push(vscode.workspace.onDidChangeNotebookDocument(() => { - count++; - })); - - const notebook = await openRandomNotebookDocument(); - await vscode.window.showNotebookDocument(notebook); - assert.strictEqual(count, 0); - }); - - test('notebook open', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first'); - assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test'); - assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript'); - - const secondCell = editor.notebook.cellAt(1); - assert.strictEqual(secondCell.outputs.length, 1); - assert.deepStrictEqual(secondCell.outputs[0].metadata, { testOutputMetadata: true, ['text/plain']: { testOutputItemMetadata: true } }); - assert.strictEqual(secondCell.outputs[0].items.length, 1); - assert.strictEqual(secondCell.outputs[0].items[0].mime, 'text/plain'); - assert.strictEqual(new TextDecoder().decode(secondCell.outputs[0].items[0].data), 'Hello World'); - assert.strictEqual(secondCell.executionSummary?.executionOrder, 5); - assert.strictEqual(secondCell.executionSummary?.success, true); - }); - - test('notebook cell actions', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); - assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first'); - assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test'); - assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript'); - - // ---- insert cell below and focus ---- // - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - assert.strictEqual(getFocusedCell(editor)?.document.getText(), ''); - - // ---- insert cell above and focus ---- // - await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); - let activeCell = getFocusedCell(editor); - assert.notStrictEqual(getFocusedCell(editor), undefined); - assert.strictEqual(activeCell!.document.getText(), ''); - assert.strictEqual(editor.notebook.cellCount, 4); - assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1); - - // ---- focus bottom ---- // - await vscode.commands.executeCommand('notebook.focusBottom'); - activeCell = getFocusedCell(editor); - assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 3); - - // ---- focus top and then copy down ---- // - await vscode.commands.executeCommand('notebook.focusTop'); - activeCell = getFocusedCell(editor); - assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 0); - - await vscode.commands.executeCommand('notebook.cell.copyDown'); - activeCell = getFocusedCell(editor); - assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1); - assert.strictEqual(activeCell?.document.getText(), 'test'); - - { - const focusedCell = getFocusedCell(editor); - assert.strictEqual(focusedCell !== undefined, true); - // delete focused cell - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(focusedCell!.notebook.uri, new vscode.NotebookRange(focusedCell!.index, focusedCell!.index + 1), []); - await vscode.workspace.applyEdit(edit); - } - - activeCell = getFocusedCell(editor); - assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1); - assert.strictEqual(activeCell?.document.getText(), ''); - - // ---- focus top and then copy up ---- // - await vscode.commands.executeCommand('notebook.focusTop'); - await vscode.commands.executeCommand('notebook.cell.copyUp'); - assert.strictEqual(editor.notebook.cellCount, 5); - assert.strictEqual(editor.notebook.cellAt(0).document.getText(), 'test'); - assert.strictEqual(editor.notebook.cellAt(1).document.getText(), 'test'); - assert.strictEqual(editor.notebook.cellAt(2).document.getText(), ''); - assert.strictEqual(editor.notebook.cellAt(3).document.getText(), ''); - activeCell = getFocusedCell(editor); - assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 0); - - - // ---- move up and down ---- // - - await vscode.commands.executeCommand('notebook.cell.moveDown'); - assert.strictEqual(editor.notebook.getCells().indexOf(getFocusedCell(editor)!), 1, - `first move down, active cell ${getFocusedCell(editor)!.document.uri.toString()}, ${getFocusedCell(editor)!.document.getText()}`); - - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - }); - - test('editor move command - event and move cells will not recreate cells in ExtHost (#98126)', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - - const activeCell = getFocusedCell(editor); - assert.strictEqual(activeCell?.index, 0); - const notebookChangeEvent = asPromise(vscode.workspace.onDidChangeNotebookDocument); - await vscode.commands.executeCommand('notebook.cell.moveDown'); - assert.ok(await notebookChangeEvent); - - const newActiveCell = getFocusedCell(editor); - assert.strictEqual(newActiveCell?.index, 1); - assert.deepStrictEqual(activeCell, newActiveCell); - }); - - // test('document runnable based on kernel count', async () => { - // const resource = await createRandomNotebookFile(); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - // assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); - // const editor = vscode.window.activeNotebookEditor!; - - // const cell = editor.notebook.cellAt(0); - // assert.strictEqual(cell.outputs.length, 0); - - // currentKernelProvider.setHasKernels(false); - // await vscode.commands.executeCommand('notebook.execute'); - // assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work - - // currentKernelProvider.setHasKernels(true); - - // await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { - // await vscode.commands.executeCommand('notebook.execute'); - // await event; - // assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - // }); - - // await saveAllFilesAndCloseAll(undefined); - // }); - - - // TODO@rebornix this is wrong, `await vscode.commands.executeCommand('notebook.execute');` doesn't wait until the workspace edit is applied - test.skip('cell execute command takes arguments', async () => { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); - const editor = vscode.window.activeNotebookEditor!; - const cell = editor.notebook.cellAt(0); - - await vscode.commands.executeCommand('notebook.execute'); - assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work - }); - - test('cell execute command takes arguments 2', async () => { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); - const editor = vscode.window.activeNotebookEditor!; - const cell = editor.notebook.cellAt(0); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { - await vscode.commands.executeCommand('notebook.execute'); - await event; - assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - }); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async event => { - await vscode.commands.executeCommand('notebook.cell.clearOutputs'); - await event; - assert.strictEqual(cell.outputs.length, 0, 'should clear'); - }); - - const secondResource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { - await vscode.commands.executeCommand('notebook.cell.execute', { start: 0, end: 1 }, resource); - await event; - assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - assert.strictEqual(vscode.window.activeNotebookEditor?.notebook.uri.fsPath, secondResource.fsPath); - }); - }); - - // #126371 - test.skip('cell execute command takes arguments ICellRange[]', async () => { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - vscode.commands.executeCommand('notebook.cell.execute', { ranges: [{ start: 0, end: 1 }, { start: 1, end: 2 }] }); - let firstCellExecuted = false; - let secondCellExecuted = false; - let resolve: () => void; - const p = new Promise(r => resolve = r); - const listener = vscode.workspace.onDidChangeNotebookDocument(e => { - e.cellChanges.forEach(change => { - if (change.cell.index === 0) { - firstCellExecuted = true; - } - - if (change.cell.index === 1) { - secondCellExecuted = true; - } - }); - - if (firstCellExecuted && secondCellExecuted) { - resolve(); - } - }); - - await p; - listener.dispose(); - await saveAllFilesAndCloseAll(); - }); - - test('document execute command takes arguments', async () => { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); - const editor = vscode.window.activeNotebookEditor!; - const cell = editor.notebook.cellAt(0); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { - await vscode.commands.executeCommand('notebook.execute'); - await event; - assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - }); - - const clearChangeEvent = asPromise(vscode.workspace.onDidChangeNotebookDocument); - await vscode.commands.executeCommand('notebook.cell.clearOutputs'); - await clearChangeEvent; - assert.strictEqual(cell.outputs.length, 0, 'should clear'); - - const secondResource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { - await vscode.commands.executeCommand('notebook.execute', resource); - await event; - assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - assert.strictEqual(vscode.window.activeNotebookEditor?.notebook.uri.fsPath, secondResource.fsPath); - }); - }); - - test('cell execute and select kernel', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first'); - - const cell = editor.notebook.cellAt(0); - - const alternativeKernel = new class extends Kernel { - constructor() { - super('secondaryKernel', 'Notebook Secondary Test Kernel'); - this.controller.supportsExecutionOrder = false; - } - - override async _runCell(cell: vscode.NotebookCell) { - const task = this.controller.createNotebookCellExecution(cell); - task.start(); - await task.replaceOutput([new vscode.NotebookCellOutput([ - vscode.NotebookCellOutputItem.text('my second output', 'text/plain') - ])]); - task.end(true); - } - }; - testDisposables.push(alternativeKernel.controller); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { - await assertKernel(defaultKernel, notebook); - await vscode.commands.executeCommand('notebook.cell.execute'); - await event; - assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - assert.strictEqual(cell.outputs[0].items.length, 1); - assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain'); - assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), cell.document.getText()); - }); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { - await assertKernel(alternativeKernel, notebook); - await vscode.commands.executeCommand('notebook.cell.execute'); - await event; - assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - assert.strictEqual(cell.outputs[0].items.length, 1); - assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain'); - assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), 'my second output'); - }); - }); - - test.skip('onDidChangeCellExecutionState is fired', async () => { // TODO@rebornix https://github.com/microsoft/vscode/issues/139350 - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const editor = vscode.window.activeNotebookEditor!; - const cell = editor.notebook.cellAt(0); - - vscode.commands.executeCommand('notebook.cell.execute'); - let eventCount = 0; - let resolve: () => void; - const p = new Promise(r => resolve = r); - const listener = vscode.notebooks.onDidChangeNotebookCellExecutionState(e => { - if (eventCount === 0) { - assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Pending, 'should be set to Pending'); - } else if (eventCount === 1) { - assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Executing, 'should be set to Executing'); - assert.strictEqual(cell.outputs.length, 0, 'no outputs yet: ' + JSON.stringify(cell.outputs[0])); - } else if (eventCount === 2) { - assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Idle, 'should be set to Idle'); - assert.strictEqual(cell.outputs.length, 1, 'should have an output'); - resolve(); - } - - eventCount++; - }); - - await p; - listener.dispose(); - }); - - test('notebook cell document workspace edit', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first'); - assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test'); - assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript'); - - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - assert.strictEqual(getFocusedCell(editor)?.document.getText(), ''); - - await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); - const activeCell = getFocusedCell(editor); - assert.notStrictEqual(getFocusedCell(editor), undefined); - assert.strictEqual(activeCell!.document.getText(), ''); - assert.strictEqual(editor.notebook.cellCount, 4); - assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1); - - await withEvent(vscode.workspace.onDidChangeTextDocument, async event => { - const edit = new vscode.WorkspaceEdit(); - edit.insert(activeCell!.document.uri, new vscode.Position(0, 0), 'var abc = 0;'); - await vscode.workspace.applyEdit(edit); - await event; - assert.strictEqual(vscode.window.activeNotebookEditor === editor, true); - assert.deepStrictEqual(editor.notebook.cellAt(1), getFocusedCell(editor)); - assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'var abc = 0;'); - }); - }); - - test.skip('multiple tabs: dirty + clean', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/140285 - const notebook = await openRandomNotebookDocument(); - await vscode.window.showNotebookDocument(notebook); - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), ''); - - await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); - const edit = new vscode.WorkspaceEdit(); - edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;'); - await vscode.workspace.applyEdit(edit); - - const secondNotebook = await openRandomNotebookDocument(); - await vscode.window.showNotebookDocument(secondNotebook); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - - // make sure that the previous dirty editor is still restored in the extension host and no data loss - assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true); - assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor)); - assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 4); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;'); - - }); - - test.skip('multiple tabs: two dirty tabs and switching', async function () { - const notebook = await openRandomNotebookDocument(); - await vscode.window.showNotebookDocument(notebook); - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), ''); - - await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); - const edit = new vscode.WorkspaceEdit(); - edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;'); - await vscode.workspace.applyEdit(edit); - - const secondNotebook = await openRandomNotebookDocument(); - await vscode.window.showNotebookDocument(secondNotebook); - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), ''); - - // switch to the first editor - await vscode.window.showNotebookDocument(notebook); - assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true); - assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor)); - assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 4); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;'); - - // switch to the second editor - await vscode.window.showNotebookDocument(secondNotebook); - assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true); - assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor)); - assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 3); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), ''); - - }); - - test('multiple tabs: different editors with same document', async function () { - - const notebook = await openRandomNotebookDocument(); - const firstNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.One }); - assert.ok(firstNotebookEditor === vscode.window.activeNotebookEditor); - - assert.strictEqual(firstNotebookEditor !== undefined, true, 'notebook first'); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.getText(), 'test'); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript'); - - const secondNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Beside }); - assert.strictEqual(secondNotebookEditor !== undefined, true, 'notebook first'); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.getText(), 'test'); - assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript'); - - assert.notStrictEqual(firstNotebookEditor, secondNotebookEditor); - assert.strictEqual(firstNotebookEditor?.notebook, secondNotebookEditor?.notebook, 'split notebook editors share the same document'); - - }); - - test.skip('#106657. Opening a notebook from markers view is broken ', async function () { - - const document = await openRandomNotebookDocument(); - const [cell] = document.getCells(); - - assert.strictEqual(vscode.window.activeNotebookEditor, undefined); - - // opening a cell-uri opens a notebook editor - await vscode.window.showTextDocument(cell.document, { viewColumn: vscode.ViewColumn.Active }); - // await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active); - - assert.strictEqual(!!vscode.window.activeNotebookEditor, true); - assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString()); - }); - - test('Cannot open notebook from cell-uri with vscode.open-command', async function () { - - const document = await openRandomNotebookDocument(); - const [cell] = document.getCells(); - - await saveAllFilesAndCloseAll(); - assert.strictEqual(vscode.window.activeNotebookEditor, undefined); - - // BUG is that the editor opener (https://github.com/microsoft/vscode/blob/8e7877bdc442f1e83a7fec51920d82b696139129/src/vs/editor/browser/services/openerService.ts#L69) - // removes the fragment if it matches something numeric. For notebooks that's not wanted... - await vscode.commands.executeCommand('vscode.open', cell.document.uri); - - assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString()); - }); - - test('#97830, #97764. Support switch to other editor types', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - const edit = new vscode.WorkspaceEdit(); - edit.insert(getFocusedCell(editor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;'); - await vscode.workspace.applyEdit(edit); - - assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'var abc = 0;'); - - // no kernel -> no default language - // assert.strictEqual(vscode.window.activeNotebookEditor!.kernel, undefined); - assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript'); - - await vscode.commands.executeCommand('vscode.openWith', notebook.uri, 'default'); - assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, notebook.uri.path); - }); - - // open text editor, pin, and then open a notebook - test('#96105 - dirty editors', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); - const edit = new vscode.WorkspaceEdit(); - edit.insert(resource, new vscode.Position(0, 0), 'var abc = 0;'); - await vscode.workspace.applyEdit(edit); - - // now it's dirty, open the resource with notebook editor should open a new one - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'notebook first'); - // assert.notStrictEqual(vscode.window.activeTextEditor, undefined); - - }); - - test('#102411 - untitled notebook creation failed', async function () { - await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: 'notebookCoreTest' }); - assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined'); - - await closeAllEditors(); - }); - - test('#102423 - copy/paste shares the same text buffer', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - let activeCell = getFocusedCell(vscode.window.activeNotebookEditor); - assert.strictEqual(activeCell?.document.getText(), 'test'); - - await vscode.commands.executeCommand('notebook.cell.copyDown'); - await vscode.commands.executeCommand('notebook.cell.edit'); - activeCell = getFocusedCell(vscode.window.activeNotebookEditor); - assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.getCells().indexOf(activeCell!), 1); - assert.strictEqual(activeCell?.document.getText(), 'test'); - - const edit = new vscode.WorkspaceEdit(); - edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;'); - await vscode.workspace.applyEdit(edit); - - assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.getCells().length, 3); - assert.notStrictEqual(vscode.window.activeNotebookEditor!.notebook.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.notebook.cellAt(1).document.getText()); - - await closeAllEditors(); - }); - - test('#115855 onDidSaveNotebookDocument', async function () { - const resource = await createRandomNotebookFile(); - const notebook = await vscode.workspace.openNotebookDocument(resource); - const editor = await vscode.window.showNotebookDocument(notebook); - - const cellsChangeEvent = asPromise(vscode.workspace.onDidChangeNotebookDocument); - await editor.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]); - }); - - const cellChangeEventRet = await cellsChangeEvent; - assert.strictEqual(cellChangeEventRet.notebook === notebook, true); - assert.strictEqual(cellChangeEventRet.notebook.isDirty, true); - - const saveEvent = asPromise(vscode.workspace.onDidSaveNotebookDocument); - - await notebook.save(); - - await saveEvent; - assert.strictEqual(notebook.isDirty, false); - }); - - test('Output changes are applied once the promise resolves', async function () { - - let called = false; - - const verifyOutputSyncKernel = new class extends Kernel { - - constructor() { - super('verifyOutputSyncKernel', ''); - } - - override async _execute(cells: vscode.NotebookCell[]) { - const [cell] = cells; - const task = this.controller.createNotebookCellExecution(cell); - task.start(); - await task.replaceOutput([new vscode.NotebookCellOutput([ - vscode.NotebookCellOutputItem.text('Some output', 'text/plain') - ])]); - assert.strictEqual(cell.notebook.cellAt(0).outputs.length, 1); - assert.deepStrictEqual(new TextDecoder().decode(cell.notebook.cellAt(0).outputs[0].items[0].data), 'Some output'); - task.end(undefined); - called = true; - } - }; - - const notebook = await openRandomNotebookDocument(); - await vscode.window.showNotebookDocument(notebook); - await assertKernel(verifyOutputSyncKernel, notebook); - await vscode.commands.executeCommand('notebook.cell.execute'); - assert.strictEqual(called, true); - verifyOutputSyncKernel.controller.dispose(); - }); - - test('executionSummary', async () => { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const editor = vscode.window.activeNotebookEditor!; - const cell = editor.notebook.cellAt(0); - - assert.strictEqual(cell.executionSummary?.success, undefined); - assert.strictEqual(cell.executionSummary?.executionOrder, undefined); - await vscode.commands.executeCommand('notebook.cell.execute'); - assert.strictEqual(cell.outputs.length, 1, 'should execute'); - assert.ok(cell.executionSummary); - assert.strictEqual(cell.executionSummary!.success, true); - assert.strictEqual(typeof cell.executionSummary!.executionOrder, 'number'); - }); - - test('initialize executionSummary', async () => { - - const document = await openRandomNotebookDocument(); - const cell = document.cellAt(0); - - assert.strictEqual(cell.executionSummary?.success, undefined); - assert.strictEqual(cell.executionSummary?.timing?.startTime, 10); - assert.strictEqual(cell.executionSummary?.timing?.endTime, 20); - - }); - - test('execution cancelled when delete while executing', async () => { - const document = await openRandomNotebookDocument(); - const cell = document.cellAt(0); - - let executionWasCancelled = false; - const cancelledKernel = new class extends Kernel { - constructor() { - super('cancelledKernel', ''); - } - - override async _execute(cells: vscode.NotebookCell[]) { - const [cell] = cells; - const exe = this.controller.createNotebookCellExecution(cell); - exe.token.onCancellationRequested(() => executionWasCancelled = true); - } - }; - testDisposables.push(cancelledKernel.controller); - - await vscode.window.showNotebookDocument(document); - await assertKernel(cancelledKernel, document); - await vscode.commands.executeCommand('notebook.cell.execute'); - - // Delete executing cell - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(cell!.notebook.uri, new vscode.NotebookRange(cell!.index, cell!.index + 1), []); - await vscode.workspace.applyEdit(edit); - - assert.strictEqual(executionWasCancelled, true); - }); - - test('appendOutput to different cell', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - const cell0 = editor.notebook.cellAt(0); - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - const cell1 = editor.notebook.cellAt(1); - - const nextCellKernel = new class extends Kernel { - constructor() { - super('nextCellKernel', 'Append to cell kernel'); - } - - override async _runCell(cell: vscode.NotebookCell) { - const task = this.controller.createNotebookCellExecution(cell); - task.start(); - await task.appendOutput([new vscode.NotebookCellOutput([ - vscode.NotebookCellOutputItem.text('my output') - ])], cell1); - await task.appendOutput([new vscode.NotebookCellOutput([ - vscode.NotebookCellOutputItem.text('my output 2') - ])], cell1); - task.end(true); - } - }; - testDisposables.push(nextCellKernel.controller); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { - await assertKernel(nextCellKernel, notebook); - await vscode.commands.executeCommand('notebook.cell.execute'); - await event; - assert.strictEqual(cell0.outputs.length, 0, 'should not change cell 0'); - assert.strictEqual(cell1.outputs.length, 2, 'should update cell 1'); - assert.strictEqual(cell1.outputs[0].items.length, 1); - assert.deepStrictEqual(new TextDecoder().decode(cell1.outputs[0].items[0].data), 'my output'); - }); - }); - - test('replaceOutput to different cell', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - const cell0 = editor.notebook.cellAt(0); - await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - const cell1 = editor.notebook.cellAt(1); - - const nextCellKernel = new class extends Kernel { - constructor() { - super('nextCellKernel', 'Replace to cell kernel'); - } - - override async _runCell(cell: vscode.NotebookCell) { - const task = this.controller.createNotebookCellExecution(cell); - task.start(); - await task.replaceOutput([new vscode.NotebookCellOutput([ - vscode.NotebookCellOutputItem.text('my output') - ])], cell1); - await task.replaceOutput([new vscode.NotebookCellOutput([ - vscode.NotebookCellOutputItem.text('my output 2') - ])], cell1); - task.end(true); - } - }; - testDisposables.push(nextCellKernel.controller); - - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { - await assertKernel(nextCellKernel, notebook); - await vscode.commands.executeCommand('notebook.cell.execute'); - await event; - assert.strictEqual(cell0.outputs.length, 0, 'should not change cell 0'); - assert.strictEqual(cell1.outputs.length, 1, 'should update cell 1'); - assert.strictEqual(cell1.outputs[0].items.length, 1); - assert.deepStrictEqual(new TextDecoder().decode(cell1.outputs[0].items[0].data), 'my output 2'); - }); - }); -}); - -(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('statusbar', () => { - const emitter = new vscode.EventEmitter(); - const onDidCallProvide = emitter.event; - const suiteDisposables: vscode.Disposable[] = []; - suiteTeardown(async function () { - assertNoRpc(); - - await revertAllDirty(); - await closeAllEditors(); - - disposeAll(suiteDisposables); - suiteDisposables.length = 0; - }); - - suiteSetup(() => { - suiteDisposables.push(vscode.notebooks.registerNotebookCellStatusBarItemProvider('notebookCoreTest', { - async provideCellStatusBarItems(cell: vscode.NotebookCell, _token: vscode.CancellationToken): Promise { - emitter.fire(cell); - return []; - } - })); - - suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider)); - }); - - test.skip('provideCellStatusBarItems called on metadata change', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/139324 - const provideCalled = asPromise(onDidCallProvide); - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - await provideCalled; - - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCellMetadata(resource, 0, { inputCollapsed: true }); - vscode.workspace.applyEdit(edit); - await provideCalled; - }); -}); - -(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('Notebook API tests (metadata)', function () { - const testDisposables: vscode.Disposable[] = []; - const suiteDisposables: vscode.Disposable[] = []; - - suiteTeardown(async function () { - assertNoRpc(); - - await revertAllDirty(); - await closeAllEditors(); - - disposeAll(suiteDisposables); - suiteDisposables.length = 0; - }); - - suiteSetup(function () { - suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider)); - }); - - setup(async function () { - await saveAllFilesAndCloseAll(); - }); - - teardown(async function () { - disposeAll(testDisposables); - testDisposables.length = 0; - await saveAllFilesAndCloseAll(); - }); - - test('custom metadata should be supported', async function () { - const notebook = await openRandomNotebookDocument(); - const editor = await vscode.window.showNotebookDocument(notebook); - - assert.strictEqual(editor.notebook.metadata.custom?.testMetadata, false); - assert.strictEqual(getFocusedCell(editor)?.metadata.custom?.testCellMetadata, 123); - assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript'); - }); -}); - -suite('Notebook & LiveShare', function () { - - const suiteDisposables: vscode.Disposable[] = []; - const notebookType = 'vsls-testing'; - - suiteTeardown(() => { - vscode.Disposable.from(...suiteDisposables).dispose(); - }); - - suiteSetup(function () { - - suiteDisposables.push(vscode.workspace.registerNotebookSerializer(notebookType, new class implements vscode.NotebookSerializer { - deserializeNotebook(content: Uint8Array, _token: vscode.CancellationToken): vscode.NotebookData | Thenable { - const value = new TextDecoder().decode(content); - const cell1 = new vscode.NotebookCellData(vscode.NotebookCellKind.Code, value, 'fooLang'); - cell1.outputs = [new vscode.NotebookCellOutput([vscode.NotebookCellOutputItem.stderr(value)])]; - return new vscode.NotebookData([cell1]); - } - serializeNotebook(data: vscode.NotebookData, _token: vscode.CancellationToken): Uint8Array | Thenable { - return new TextEncoder().encode(data.cells[0].value); - } - }, {}, { - displayName: 'LS', - filenamePattern: ['*'], - })); - }); - - test('command: vscode.resolveNotebookContentProviders', async function () { - - type Info = { viewType: string; displayName: string; filenamePattern: string[] }; - - const info = await vscode.commands.executeCommand('vscode.resolveNotebookContentProviders'); - assert.strictEqual(Array.isArray(info), true); - - const item = info.find(item => item.viewType === notebookType); - assert.ok(item); - assert.strictEqual(item?.viewType, notebookType); - }); - - test('command: vscode.executeDataToNotebook', async function () { - const value = 'dataToNotebook'; - const data = await vscode.commands.executeCommand('vscode.executeDataToNotebook', notebookType, new TextEncoder().encode(value)); - assert.ok(data instanceof vscode.NotebookData); - assert.strictEqual(data.cells.length, 1); - assert.strictEqual(data.cells[0].value, value); - assert.strictEqual(new TextDecoder().decode(data.cells[0].outputs![0].items[0].data), value); - }); - - test('command: vscode.executeNotebookToData', async function () { - const value = 'notebookToData'; - const notebook = new vscode.NotebookData([new vscode.NotebookCellData(vscode.NotebookCellKind.Code, value, 'fooLang')]); - const data = await vscode.commands.executeCommand('vscode.executeNotebookToData', notebookType, notebook); - assert.ok(data instanceof Uint8Array); - assert.deepStrictEqual(new TextDecoder().decode(data), value); - }); -}); 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 3fa4ed05599..b76e348e02e 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { deepStrictEqual, doesNotThrow, equal, strictEqual, throws } from 'assert'; -import { ConfigurationTarget, Disposable, env, EnvironmentVariableMutator, EnvironmentVariableMutatorType, EventEmitter, ExtensionContext, extensions, ExtensionTerminalOptions, Pseudoterminal, Terminal, TerminalDimensions, TerminalOptions, TerminalState, UIKind, window, workspace } from 'vscode'; +import { ConfigurationTarget, Disposable, env, EnvironmentVariableMutator, EnvironmentVariableMutatorType, EventEmitter, ExtensionContext, extensions, ExtensionTerminalOptions, Pseudoterminal, Terminal, TerminalDimensions, TerminalExitReason, TerminalOptions, TerminalState, UIKind, window, workspace } from 'vscode'; import { assertNoRpc, poll } from '../utils'; // Disable terminal tests: @@ -223,7 +223,7 @@ import { assertNoRpc, poll } from '../utils'; await new Promise(r => { disposables.push(window.onDidCloseTerminal(t => { if (t === terminal) { - deepStrictEqual(t.exitStatus, { code: undefined }); + deepStrictEqual(t.exitStatus, { code: undefined, reason: TerminalExitReason.Extension }); r(); } })); @@ -579,7 +579,7 @@ import { assertNoRpc, poll } from '../utils'; strictEqual(created.exitStatus, undefined); disposables.push(window.onDidCloseTerminal(t2 => { if (t2 === created) { - deepStrictEqual(created.exitStatus, { code: undefined }); + deepStrictEqual(created.exitStatus, { code: undefined, reason: TerminalExitReason.Process }); r(); } })); @@ -604,7 +604,7 @@ import { assertNoRpc, poll } from '../utils'; strictEqual(created.exitStatus, undefined); disposables.push(window.onDidCloseTerminal(t2 => { if (t2 === created) { - deepStrictEqual(created.exitStatus, { code: 0 }); + deepStrictEqual(created.exitStatus, { code: 0, reason: TerminalExitReason.Process }); r(); } })); @@ -634,7 +634,7 @@ import { assertNoRpc, poll } from '../utils'; strictEqual(created.exitStatus, undefined); disposables.push(window.onDidCloseTerminal(t2 => { if (t2 === created) { - deepStrictEqual(created.exitStatus, { code: 22 }); + deepStrictEqual(created.exitStatus, { code: 22, reason: TerminalExitReason.Process }); r(); } })); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts deleted file mode 100644 index d9c199ea50e..00000000000 --- a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts +++ /dev/null @@ -1,578 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as os from 'os'; -import * as vscode from 'vscode'; -import { assertNoRpc, closeAllEditors, delay, disposeAll } from '../utils'; - -const webviewId = 'myWebview'; - -function workspaceFile(...segments: string[]) { - return vscode.Uri.joinPath(vscode.workspace.workspaceFolders![0].uri, ...segments); -} - -suite.skip('vscode API - webview', () => { // TODO@mjbvz https://github.com/microsoft/vscode/issues/153066 - const disposables: vscode.Disposable[] = []; - - function _register(disposable: T) { - disposables.push(disposable); - return disposable; - } - - teardown(async () => { - assertNoRpc(); - await closeAllEditors(); - disposeAll(disposables); - }); - - test.skip('webviews should be able to send and receive messages', async () => { // TODO@mjbvz https://github.com/microsoft/vscode/issues/150682 - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true })); - const firstResponse = getMessage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - - webview.webview.postMessage({ value: 1 }); - assert.strictEqual((await firstResponse).value, 2); - }); - - test('webviews should not have scripts enabled by default', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, {})); - const response = Promise.race([ - getMessage(webview), - new Promise<{}>(resolve => setTimeout(() => resolve({ value: '🎉' }), 1000)) - ]); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - - assert.strictEqual((await response).value, '🎉'); - }); - - test('webviews should update html', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true })); - - { - const response = getMessage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - - assert.strictEqual((await response).value, 'first'); - } - { - const response = getMessage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - - assert.strictEqual((await response).value, 'second'); - } - }); - - test.skip('webviews should preserve vscode API state when they are hidden', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true })); - const ready = getMessage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - await ready; - - const firstResponse = await sendReceiveMessage(webview, { type: 'add' }); - assert.strictEqual(firstResponse.value, 1); - - // Swap away from the webview - const doc = await vscode.workspace.openTextDocument(workspaceFile('bower.json')); - await vscode.window.showTextDocument(doc); - - // And then back - const ready2 = getMessage(webview); - webview.reveal(vscode.ViewColumn.One); - await ready2; - - // We should still have old state - const secondResponse = await sendReceiveMessage(webview, { type: 'get' }); - assert.strictEqual(secondResponse.value, 1); - }); - - test.skip('webviews should preserve their context when they are moved between view columns', async () => { // TODO@mjbvz https://github.com/microsoft/vscode/issues/141001 - const doc = await vscode.workspace.openTextDocument(workspaceFile('bower.json')); - await vscode.window.showTextDocument(doc, vscode.ViewColumn.One); - - // Open webview in same column - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true })); - const ready = getMessage(webview); - webview.webview.html = statefulWebviewHtml; - await ready; - - const firstResponse = await sendReceiveMessage(webview, { type: 'add' }); - assert.strictEqual(firstResponse.value, 1); - - // Now move webview to new view column - webview.reveal(vscode.ViewColumn.Two); - - // We should still have old state - const secondResponse = await sendReceiveMessage(webview, { type: 'get' }); - assert.strictEqual(secondResponse.value, 1); - }); - - test.skip('webviews with retainContextWhenHidden should preserve their context when they are hidden', async function () { - this.retries(3); - - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); - const ready = getMessage(webview); - - webview.webview.html = statefulWebviewHtml; - await ready; - - const firstResponse = await sendReceiveMessage(webview, { type: 'add' }); - assert.strictEqual((await firstResponse).value, 1); - - // Swap away from the webview - const doc = await vscode.workspace.openTextDocument(workspaceFile('bower.json')); - await vscode.window.showTextDocument(doc); - - // And then back - webview.reveal(vscode.ViewColumn.One); - - // We should still have old state - const secondResponse = await sendReceiveMessage(webview, { type: 'get' }); - assert.strictEqual(secondResponse.value, 1); - }); - - test.skip('webviews with retainContextWhenHidden should preserve their page position when hidden', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); - const ready = getMessage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - ${'

Header

'.repeat(200)} - `); - await ready; - - const firstResponse = getMessage(webview); - - assert.strictEqual(Math.round((await firstResponse).value), 100); - - // Swap away from the webview - const doc = await vscode.workspace.openTextDocument(workspaceFile('bower.json')); - await vscode.window.showTextDocument(doc); - - // And then back - webview.reveal(vscode.ViewColumn.One); - - // We should still have old scroll pos - const secondResponse = await sendReceiveMessage(webview, { type: 'get' }); - assert.strictEqual(Math.round(secondResponse.value), 100); - }); - - test.skip('webviews with retainContextWhenHidden should be able to recive messages while hidden', async () => { // TODO@mjbvz https://github.com/microsoft/vscode/issues/139960 - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); - const ready = getMessage(webview); - - webview.webview.html = statefulWebviewHtml; - await ready; - - const firstResponse = await sendReceiveMessage(webview, { type: 'add' }); - assert.strictEqual((await firstResponse).value, 1); - - // Swap away from the webview - const doc = await vscode.workspace.openTextDocument(workspaceFile('bower.json')); - await vscode.window.showTextDocument(doc); - - // Try posting a message to our hidden webview - const secondResponse = await sendReceiveMessage(webview, { type: 'add' }); - assert.strictEqual((await secondResponse).value, 2); - - // Now show webview again - webview.reveal(vscode.ViewColumn.One); - - // We should still have old state - const thirdResponse = await sendReceiveMessage(webview, { type: 'get' }); - assert.strictEqual(thirdResponse.value, 2); - }); - - - test.skip('webviews should only be able to load resources from workspace by default', async () => { // TODO@mjbvz https://github.com/microsoft/vscode/issues/139960 - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { - viewColumn: vscode.ViewColumn.One - }, { - enableScripts: true - })); - - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - - const ready = getMessage(webview); - if ((await ready).userAgent.indexOf('Firefox') >= 0) { - // Skip on firefox web for now. - // Firefox service workers never seem to get any 'fetch' requests here. Other browsers work fine - return; - } - - { - const imagePath = webview.webview.asWebviewUri(workspaceFile('image.png')); - const response = await sendReceiveMessage(webview, { src: imagePath.toString() }); - assert.strictEqual(response.value, true); - } - // { - // // #102188. Resource filename containing special characters like '%', '#', '?'. - // const imagePath = webview.webview.asWebviewUri(workspaceFile('image%02.png')); - // const response = await sendReceiveMessage(webview, { src: imagePath.toString() }); - // assert.strictEqual(response.value, true); - // } - // { - // // #102188. Resource filename containing special characters like '%', '#', '?'. - // const imagePath = webview.webview.asWebviewUri(workspaceFile('image%.png')); - // const response = await sendReceiveMessage(webview, { src: imagePath.toString() }); - // assert.strictEqual(response.value, true); - // } - { - const imagePath = webview.webview.asWebviewUri(workspaceFile('no-such-image.png')); - const response = await sendReceiveMessage(webview, { src: imagePath.toString() }); - assert.strictEqual(response.value, false); - } - { - const imagePath = webview.webview.asWebviewUri(workspaceFile('..', '..', '..', 'resources', 'linux', 'code.png')); - const response = await sendReceiveMessage(webview, { src: imagePath.toString() }); - assert.strictEqual(response.value, false); - } - }); - - test.skip('webviews should allow overriding allowed resource paths using localResourceRoots', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { - enableScripts: true, - localResourceRoots: [workspaceFile('sub')] - })); - - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - - { - const response = sendReceiveMessage(webview, { src: webview.webview.asWebviewUri(workspaceFile('sub', 'image.png')).toString() }); - assert.strictEqual((await response).value, true); - } - { - const response = sendReceiveMessage(webview, { src: webview.webview.asWebviewUri(workspaceFile('image.png')).toString() }); - assert.strictEqual((await response).value, false); - } - }); - - test.skip('webviews using hard-coded old style vscode-resource uri should work', async () => { // TODO@mjbvz https://github.com/microsoft/vscode/issues/139572 - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { - enableScripts: true, - localResourceRoots: [workspaceFile('sub')] - })); - - const imagePath = workspaceFile('sub', 'image.png').with({ scheme: 'vscode-resource' }).toString(); - - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - - `); - - const ready = getMessage(webview); - if ((await ready).userAgent.indexOf('Firefox') >= 0) { - // Skip on firefox web for now. - // Firefox service workers never seem to get any 'fetch' requests here. Other browsers work fine - return; - } - const firstResponse = await sendReceiveMessage(webview, { src: imagePath.toString() }); - - assert.strictEqual(firstResponse.value, true); - }); - - test('webviews should have real view column after they are created, #56097', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.Active }, { enableScripts: true })); - - // Since we used a symbolic column, we don't know what view column the webview will actually show in at first - assert.strictEqual(webview.viewColumn, undefined); - - let changed = false; - const viewStateChanged = new Promise((resolve) => { - webview.onDidChangeViewState(e => { - if (changed) { - throw new Error('Only expected a single view state change'); - } - changed = true; - resolve(e); - }, undefined, disposables); - }); - - assert.strictEqual((await viewStateChanged).webviewPanel.viewColumn, vscode.ViewColumn.One); - - const firstResponse = getMessage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - - webview.webview.postMessage({ value: 1 }); - await firstResponse; - assert.strictEqual(webview.viewColumn, vscode.ViewColumn.One); - }); - - if (os.platform() === 'darwin') { - test.skip('webview can copy text from webview', async () => { - const expectedText = `webview text from: ${Date.now()}!`; - - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); - const ready = getMessage(webview); - - - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - ${expectedText} - `); - await ready; - - await vscode.commands.executeCommand('editor.action.clipboardCopyAction'); - await delay(200); // Make sure copy has time to reach webview - assert.strictEqual(await vscode.env.clipboard.readText(), expectedText); - }); - } - - test.skip('webviews should transfer ArrayBuffers to and from webviews', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); - const ready = getMessage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - await ready; - - const responsePromise = getMessage(webview); - - const bufferLen = 100; - - { - const arrayBuffer = new ArrayBuffer(bufferLen); - const uint8Array = new Uint8Array(arrayBuffer); - for (let i = 0; i < bufferLen; ++i) { - uint8Array[i] = i; - } - webview.webview.postMessage({ - type: 'add1', - array: arrayBuffer - }); - } - { - const response = await responsePromise; - assert.ok(response.array instanceof ArrayBuffer); - - const uint8Array = new Uint8Array(response.array); - for (let i = 0; i < bufferLen; ++i) { - assert.strictEqual(uint8Array[i], i + 1); - } - } - }); - - test.skip('webviews should transfer Typed arrays to and from webviews', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); - const ready = getMessage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); - await ready; - - const responsePromise = getMessage(webview); - - const bufferLen = 100; - { - const arrayBuffer = new ArrayBuffer(bufferLen); - const uint8Array = new Uint8Array(arrayBuffer); - const uint16Array = new Uint16Array(arrayBuffer); - for (let i = 0; i < uint16Array.length; ++i) { - uint16Array[i] = i; - } - - webview.webview.postMessage({ - type: 'add1', - array1: uint8Array, - array2: uint16Array, - }); - } - { - const response = await responsePromise; - - assert.ok(response.array1 instanceof Uint8Array); - assert.ok(response.array2 instanceof Uint16Array); - assert.ok(response.array1.buffer === response.array2.buffer); - - const uint8Array = response.array1; - for (let i = 0; i < bufferLen; ++i) { - if (i % 2 === 0) { - assert.strictEqual(uint8Array[i], Math.floor(i / 2) + 1); - } else { - assert.strictEqual(uint8Array[i], 0); - } - } - } - }); -}); - -function createHtmlDocumentWithBody(body: string): string { - return /*html*/` - - - - - - Document - - - ${body} - -`; -} - -const statefulWebviewHtml = createHtmlDocumentWithBody(/*html*/ ` - `); - - -function getMessage(webview: vscode.WebviewPanel): Promise { - return new Promise(resolve => { - const sub = webview.webview.onDidReceiveMessage(message => { - sub.dispose(); - resolve(message); - }); - }); -} - -function sendReceiveMessage(webview: vscode.WebviewPanel, message: T): Promise { - const p = getMessage(webview); - webview.webview.postMessage(message); - return p; -} diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts index 5a9825d77b9..e32589a6800 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { join } from 'path'; -import { CancellationTokenSource, commands, MarkdownString, TabInputNotebook, Position, QuickPickItem, Selection, StatusBarAlignment, TextEditor, TextEditorSelectionChangeKind, TextEditorViewColumnChangeEvent, TabInputText, Uri, ViewColumn, window, workspace, TabInputTextDiff } from 'vscode'; +import { CancellationTokenSource, commands, MarkdownString, TabInputNotebook, Position, QuickPickItem, Selection, StatusBarAlignment, TextEditor, TextEditorSelectionChangeKind, TextEditorViewColumnChangeEvent, TabInputText, Uri, ViewColumn, window, workspace, TabInputTextDiff, UIKind, env } from 'vscode'; import { assertNoRpc, closeAllEditors, createRandomFile, pathEquals } from '../utils'; @@ -449,7 +449,7 @@ suite('vscode API - window', () => { assert.strictEqual(tabs[3].input.uri.toString(), commandFile.toString()); }); - test('Tabs - Ensure tabs getter is correct', async function () { + (env.uiKind === UIKind.Web ? test.skip : test)('Tabs - Ensure tabs getter is correct', async function () { // Reduce test timeout as this test should be quick, so even with 3 retries it will be under 60s. this.timeout(10000); // This test can be flaky because of opening a notebook diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index 6e088ce9ee5..f1b76a3e515 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -131,14 +131,16 @@ suite('vscode API - workspace', () => { assert.strictEqual(doc.uri.scheme, 'untitled'); assert.ok(doc.isDirty); - let closed: vscode.TextDocument; - const d0 = vscode.workspace.onDidCloseTextDocument(e => closed = e); + const closedDocuments: vscode.TextDocument[] = []; + const d0 = vscode.workspace.onDidCloseTextDocument(e => closedDocuments.push(e)); return vscode.window.showTextDocument(doc).then(() => { return doc.save().then((didSave: boolean) => { assert.strictEqual(didSave, true, `FAILED to save${doc.uri.toString()}`); + const closed = closedDocuments.filter(close => close.uri.toString() === doc.uri.toString())[0]; + assert.ok(closed); assert.ok(closed === doc); assert.ok(!doc.isDirty); assert.ok(fs.existsSync(path)); @@ -1147,4 +1149,41 @@ suite('vscode API - workspace', () => { assert.strictEqual(document.isDirty, false); } }); + + test('SnippetString in WorkspaceEdit', async function (): Promise { + const file = await createRandomFile('hello\nworld'); + + const document = await vscode.workspace.openTextDocument(file); + const edt = await vscode.window.showTextDocument(document); + + assert.ok(edt === vscode.window.activeTextEditor); + + const we = new vscode.WorkspaceEdit(); + we.set(document.uri, [new vscode.SnippetTextEdit(new vscode.Range(0, 0, 0, 0), new vscode.SnippetString('${1:foo}${2:bar}'))]); + const success = await vscode.workspace.applyEdit(we); + if (edt !== vscode.window.activeTextEditor) { + return this.skip(); + } + + assert.ok(success); + assert.strictEqual(document.getText(), 'foobarhello\nworld'); + assert.deepStrictEqual(edt.selections, [new vscode.Selection(0, 0, 0, 3)]); + }); + + + test('Support creating binary files in a WorkspaceEdit', async function (): Promise { + + const fileUri = vscode.Uri.parse(`${testFs.scheme}:/${rndName()}`); + const data = Buffer.from('Hello Binary Files'); + + const ws = new vscode.WorkspaceEdit(); + ws.createFile(fileUri, { contents: data, ignoreIfExists: false, overwrite: false }); + + const success = await vscode.workspace.applyEdit(ws); + assert.ok(success); + + const actual = await vscode.workspace.fs.readFile(fileUri); + + assert.deepStrictEqual(actual, data); + }); }); diff --git a/extensions/vscode-api-tests/src/utils.ts b/extensions/vscode-api-tests/src/utils.ts index c5a8e58483f..7c506694289 100644 --- a/extensions/vscode-api-tests/src/utils.ts +++ b/extensions/vscode-api-tests/src/utils.ts @@ -125,11 +125,12 @@ export function assertNoRpcFromEntry(entry: [obj: any, name: string]) { } export async function asPromise(event: vscode.Event, timeout = vscode.env.uiKind === vscode.UIKind.Desktop ? 5000 : 15000): Promise { + const error = new Error('asPromise TIMEOUT reached'); return new Promise((resolve, reject) => { const handle = setTimeout(() => { sub.dispose(); - reject(new Error('asPromise TIMEOUT reached')); + reject(error); }, timeout); const sub = event(e => { @@ -183,3 +184,61 @@ export async function poll( trial++; } } + +export type ValueCallback = (value: T | Promise) => void; + +/** + * Creates a promise whose resolution or rejection can be controlled imperatively. + */ +export class DeferredPromise { + + private completeCallback!: ValueCallback; + private errorCallback!: (err: unknown) => void; + private rejected = false; + private resolved = false; + + public get isRejected() { + return this.rejected; + } + + public get isResolved() { + return this.resolved; + } + + public get isSettled() { + return this.rejected || this.resolved; + } + + public readonly p: Promise; + + constructor() { + this.p = new Promise((c, e) => { + this.completeCallback = c; + this.errorCallback = e; + }); + } + + public complete(value: T) { + return new Promise(resolve => { + this.completeCallback(value); + this.resolved = true; + resolve(); + }); + } + + public error(err: unknown) { + return new Promise(resolve => { + this.errorCallback(err); + this.rejected = true; + resolve(); + }); + } + + public cancel() { + new Promise(resolve => { + this.errorCallback(new Error('Canceled')); + this.rejected = true; + resolve(); + }); + } +} diff --git a/extensions/vscode-colorize-tests/test/colorize-fixtures/makefile b/extensions/vscode-colorize-tests/test/colorize-fixtures/makefile index 3f77d04fa52..32daa0c97af 100644 --- a/extensions/vscode-colorize-tests/test/colorize-fixtures/makefile +++ b/extensions/vscode-colorize-tests/test/colorize-fixtures/makefile @@ -77,6 +77,10 @@ var!=echo val var:=val \ notvar=butval var:=$(val:.c=.o) +var:=blah#comment +var?=blah\#not_a_comment +var:=blah\\#comment +var!=blah\\\#not_a_comment var-$(nested-var)=val diff --git a/extensions/vscode-colorize-tests/test/colorize-results/makefile.json b/extensions/vscode-colorize-tests/test/colorize-results/makefile.json index a3abf6bf666..ecaa0f00373 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/makefile.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/makefile.json @@ -252,7 +252,31 @@ } }, { - "c": " second,second", + "c": " second", + "t": "source.makefile meta.scope.target.makefile meta.scope.prerequisites.makefile string.interpolated.makefile string.interpolated.makefile meta.scope.function-call.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": ",", + "t": "source.makefile meta.scope.target.makefile meta.scope.prerequisites.makefile string.interpolated.makefile string.interpolated.makefile meta.scope.function-call.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": "second", "t": "source.makefile meta.scope.target.makefile meta.scope.prerequisites.makefile string.interpolated.makefile string.interpolated.makefile meta.scope.function-call.makefile", "r": { "dark_plus": "string: #CE9178", @@ -1572,7 +1596,7 @@ } }, { - "c": " undefined,", + "c": " undefined", "t": "source.makefile meta.scope.conditional.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile", "r": { "dark_plus": "string: #CE9178", @@ -1583,6 +1607,18 @@ "hc_light": "string: #0F4A85" } }, + { + "c": ",", + "t": "source.makefile meta.scope.conditional.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, { "c": "$(", "t": "source.makefile meta.scope.conditional.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile punctuation.definition.variable.makefile", @@ -1680,7 +1716,43 @@ } }, { - "c": ",0,1", + "c": ",", + "t": "source.makefile meta.scope.conditional.makefile string.interpolated.makefile meta.scope.function-call.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": "0", + "t": "source.makefile meta.scope.conditional.makefile string.interpolated.makefile meta.scope.function-call.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": ",", + "t": "source.makefile meta.scope.conditional.makefile string.interpolated.makefile meta.scope.function-call.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": "1", "t": "source.makefile meta.scope.conditional.makefile string.interpolated.makefile meta.scope.function-call.makefile", "r": { "dark_plus": "string: #CE9178", @@ -1800,7 +1872,31 @@ } }, { - "c": " defined,TOP_DIR", + "c": " defined", + "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": ",", + "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": "TOP_DIR", "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile", "r": { "dark_plus": "string: #CE9178", @@ -1836,7 +1932,19 @@ } }, { - "c": ",0)", + "c": ",", + "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "0)", "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile", "r": { "dark_plus": "default: #D4D4D4", @@ -2076,7 +2184,31 @@ } }, { - "c": " defined,CODIT_DIR", + "c": " defined", + "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": ",", + "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178", + "hc_light": "string: #0F4A85" + } + }, + { + "c": "CODIT_DIR", "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile string.interpolated.makefile meta.scope.function-call.makefile string.interpolated.makefile meta.scope.function-call.makefile", "r": { "dark_plus": "string: #CE9178", @@ -2112,7 +2244,19 @@ } }, { - "c": ",0)", + "c": ",", + "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "0)", "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile", "r": { "dark_plus": "default: #D4D4D4", @@ -2688,7 +2832,31 @@ } }, { - "c": "\", \"skip\")", + "c": "\"", + "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": ",", + "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile punctuation.separator.delimeter.comma.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": " \"skip\")", "t": "source.makefile meta.scope.conditional.makefile meta.scope.condition.makefile", "r": { "dark_plus": "default: #D4D4D4", @@ -3359,6 +3527,198 @@ "hc_light": "string: #0F4A85" } }, + { + "c": "var", + "t": "source.makefile variable.other.makefile", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE", + "hc_light": "variable: #001080" + } + }, + { + "c": ":=", + "t": "source.makefile punctuation.separator.key-value.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "blah", + "t": "source.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "#", + "t": "source.makefile comment.line.number-sign.makefile punctuation.definition.comment.makefile", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668", + "hc_light": "comment: #515151" + } + }, + { + "c": "comment", + "t": "source.makefile comment.line.number-sign.makefile", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668", + "hc_light": "comment: #515151" + } + }, + { + "c": "var", + "t": "source.makefile variable.other.makefile", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE", + "hc_light": "variable: #001080" + } + }, + { + "c": "?=", + "t": "source.makefile punctuation.separator.key-value.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "blah\\#not_a_comment", + "t": "source.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "var", + "t": "source.makefile variable.other.makefile", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE", + "hc_light": "variable: #001080" + } + }, + { + "c": ":=", + "t": "source.makefile punctuation.separator.key-value.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "blah\\\\", + "t": "source.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "#", + "t": "source.makefile comment.line.number-sign.makefile punctuation.definition.comment.makefile", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668", + "hc_light": "comment: #515151" + } + }, + { + "c": "comment", + "t": "source.makefile comment.line.number-sign.makefile", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668", + "hc_light": "comment: #515151" + } + }, + { + "c": "var", + "t": "source.makefile variable.other.makefile", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE", + "hc_light": "variable: #001080" + } + }, + { + "c": "!=", + "t": "source.makefile punctuation.separator.key-value.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "blah\\\\\\#not_a_comment", + "t": "source.makefile", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, { "c": "var-", "t": "source.makefile variable.other.makefile", diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_fs.json b/extensions/vscode-colorize-tests/test/colorize-results/test_fs.json index f417b2ef010..499e9a81515 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_fs.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_fs.json @@ -744,7 +744,7 @@ } }, { - "c": " set", + "c": " ", "t": "source.fsharp binding.fsharp", "r": { "dark_plus": "default: #D4D4D4", @@ -755,6 +755,18 @@ "hc_light": "default: #292929" } }, + { + "c": "set", + "t": "source.fsharp binding.fsharp variable.fsharp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE", + "hc_light": "variable: #001080" + } + }, { "c": "(", "t": "source.fsharp binding.fsharp keyword.symbol.fsharp", diff --git a/extensions/yarn.lock b/extensions/yarn.lock index da2bcfbff02..1c8d7a5fc84 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -42,10 +42,10 @@ node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== -typescript@4.7.3: - version "4.7.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" - integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== +typescript@4.8.2: + version "4.8.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" + integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== vscode-grammar-updater@^1.1.0: version "1.1.0" diff --git a/package.json b/package.json index 0c567bb015c..9d4aae4a959 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", - "version": "1.69.0", - "distro": "daf000367ee34d716c5dbdf836b11c06c407ef5f", + "version": "1.72.0", + "distro": "eea401154047e2d93bd99e942f52ddffe7bb657b", "author": { "name": "Microsoft Corporation" }, @@ -56,19 +56,18 @@ "minify-vscode-reh-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode-reh-web", "hygiene": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js hygiene", "core-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js core-ci", - "extensions-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js extensions-ci" + "extensions-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js extensions-ci", + "webview-generate-csp-hash": "npx github:apaatsio/csp-hash-from-html csp-hash ./src/vs/workbench/contrib/webview/browser/pre/index.html" }, "dependencies": { "@microsoft/1ds-core-js": "^3.2.2", "@microsoft/1ds-post-js": "^3.2.2", - "@microsoft/applicationinsights-web": "^2.8.4", "@parcel/watcher": "2.0.5", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/ripgrep": "^1.14.2", "@vscode/sqlite3": "5.0.8", "@vscode/sudo-prompt": "9.3.1", "@vscode/vscode-languagedetection": "1.0.21", - "applicationinsights": "1.4.2", "graceful-fs": "4.2.8", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.3", @@ -87,19 +86,21 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "4.19.0", - "xterm-addon-search": "0.9.0", - "xterm-addon-serialize": "0.7.0", - "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0", - "xterm-headless": "4.19.0", + "xterm": "5.0.0-beta.54", + "xterm-addon-canvas": "0.2.0-beta.23", + "xterm-addon-search": "0.10.0-beta.6", + "xterm-addon-serialize": "0.8.0-beta.6", + "xterm-addon-unicode11": "0.4.0-beta.5", + "xterm-addon-webgl": "0.13.0-beta.49", + "xterm-headless": "5.0.0-beta.5", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, "devDependencies": { "7zip": "0.0.6", - "@playwright/test": "1.21.0", - "@types/applicationinsights": "0.20.0", + "@playwright/test": "1.24.2", + "@swc/cli": "0.1.57", + "@swc/core": "1.2.245", "@types/cookie": "^0.3.3", "@types/copy-webpack-plugin": "^6.0.3", "@types/cssnano": "^4.0.0", @@ -125,9 +126,10 @@ "@types/yauzl": "^2.9.1", "@types/yazl": "^2.4.2", "@typescript-eslint/eslint-plugin": "^5.10.0", + "@typescript-eslint/experimental-utils": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", - "@vscode/telemetry-extractor": "^1.9.6", - "@vscode/test-web": "^0.0.22", + "@vscode/telemetry-extractor": "^1.9.8", + "@vscode/test-web": "^0.0.29", "ansi-colors": "^3.2.3", "asar": "^3.0.3", "chromium-pickle-js": "^0.2.0", @@ -138,10 +140,11 @@ "cssnano": "^4.1.11", "debounce": "^1.0.0", "deemon": "^1.4.0", - "electron": "18.3.5", + "electron": "19.0.12", "eslint": "8.7.0", "eslint-plugin-header": "3.1.1", "eslint-plugin-jsdoc": "^39.3.2", + "eslint-plugin-local": "^1.0.0", "event-stream": "3.3.4", "fancy-log": "^1.3.3", "fast-plist": "0.1.2", @@ -171,11 +174,11 @@ "husky": "^0.13.1", "innosetup": "6.0.5", "is": "^3.1.0", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.2.0", "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.1.5", "lazy.js": "^0.4.2", "merge-options": "^1.0.1", "mime": "^1.4.1", @@ -201,8 +204,9 @@ "source-map-support": "^0.3.2", "style-loader": "^1.3.0", "ts-loader": "^9.2.7", + "ts-node": "^10.9.1", "tsec": "0.1.4", - "typescript": "^4.8.0-dev.20220614", + "typescript": "^4.9.0-dev.20220825", "typescript-formatter": "7.1.0", "underscore": "^1.12.1", "util": "^0.12.4", diff --git a/product.json b/product.json index a50c00f6cf3..d97f6cc80b5 100644 --- a/product.json +++ b/product.json @@ -27,7 +27,7 @@ "licenseFileName": "LICENSE.txt", "reportIssueUrl": "https://github.com/microsoft/vscode/issues/new", "urlProtocol": "code-oss", - "webviewContentExternalBaseUrlTemplate": "https://{{uuid}}.vscode-cdn.net/insider/3c8520fab514b9f56070214496b26ff68d1b1cb5/out/vs/workbench/contrib/webview/browser/pre/", + "webviewContentExternalBaseUrlTemplate": "https://{{uuid}}.vscode-cdn.net/insider/ef65ac1ba57f57f2a3961bfe94aa20481caca4c6/out/vs/workbench/contrib/webview/browser/pre/", "builtInExtensions": [ { "name": "ms-vscode.js-debug-companion", @@ -46,7 +46,7 @@ }, { "name": "ms-vscode.js-debug", - "version": "1.69.0", + "version": "1.71.1", "repo": "https://github.com/microsoft/vscode-js-debug", "metadata": { "id": "25629058-ddac-4e17-abba-74678e126c5d", @@ -61,7 +61,7 @@ }, { "name": "ms-vscode.vscode-js-profile-table", - "version": "1.0.2", + "version": "1.0.3", "repo": "https://github.com/microsoft/vscode-js-profile-visualizer", "metadata": { "id": "7e52b41b-71ad-457b-ab7e-0620f1fc4feb", diff --git a/remote/.yarnrc b/remote/.yarnrc index 290849a6e63..3a3fbdc3350 100644 --- a/remote/.yarnrc +++ b/remote/.yarnrc @@ -1,4 +1,4 @@ disturl "http://nodejs.org/dist" -target "16.13.2" +target "16.14.2" runtime "node" build_from_source "true" diff --git a/remote/package.json b/remote/package.json index d9300a7cb68..d34e30223c7 100644 --- a/remote/package.json +++ b/remote/package.json @@ -5,12 +5,10 @@ "dependencies": { "@microsoft/1ds-core-js": "^3.2.2", "@microsoft/1ds-post-js": "^3.2.2", - "@microsoft/applicationinsights-web": "^2.8.4", "@parcel/watcher": "2.0.5", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/ripgrep": "^1.14.2", "@vscode/vscode-languagedetection": "1.0.21", - "applicationinsights": "1.4.2", "cookie": "^0.4.0", "graceful-fs": "4.2.8", "http-proxy-agent": "^2.1.0", @@ -26,12 +24,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "4.19.0", - "xterm-addon-search": "0.9.0", - "xterm-addon-serialize": "0.7.0", - "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0", - "xterm-headless": "4.19.0", + "xterm": "5.0.0-beta.54", + "xterm-addon-canvas": "0.2.0-beta.23", + "xterm-addon-search": "0.10.0-beta.6", + "xterm-addon-serialize": "0.8.0-beta.6", + "xterm-addon-unicode11": "0.4.0-beta.5", + "xterm-addon-webgl": "0.13.0-beta.49", + "xterm-headless": "5.0.0-beta.5", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index d73ebade4f4..428d0f52a05 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -5,16 +5,16 @@ "dependencies": { "@microsoft/1ds-core-js": "^3.2.2", "@microsoft/1ds-post-js": "^3.2.2", - "@microsoft/applicationinsights-web": "^2.8.4", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/vscode-languagedetection": "1.0.21", "jschardet": "3.0.0", "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "4.19.0", - "xterm-addon-search": "0.9.0", - "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0" + "xterm": "5.0.0-beta.54", + "xterm-addon-canvas": "0.2.0-beta.23", + "xterm-addon-search": "0.10.0-beta.6", + "xterm-addon-unicode11": "0.4.0-beta.5", + "xterm-addon-webgl": "0.13.0-beta.49" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 3f341e728fa..b117c32ad58 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -20,35 +20,6 @@ "@microsoft/applicationinsights-shims" "^2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-analytics-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-2.8.4.tgz#3b32d8a2122be5d5993c74ef3217ebbf4876ea69" - integrity sha512-n/FPs8SS6rB8h+u157fiRh0TwUWKctxGNvr4M+LKeSdgDvf9c759gUeMR7r8xF6kBBfgkbmyaVORjsA1WJsU4g== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-channel-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-2.8.4.tgz#6de7210d87e61c72d3a9a06cbaeae14e1b543484" - integrity sha512-aml49Jya8LxX4tvyBbIvcxSo7UGI0k3HeiJQRFLeO+QlA+Ocsl10PqphU/OYJ4hh/P5/2QhEAq5bBM/b9/PNrg== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-common@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-common/-/applicationinsights-common-2.8.4.tgz#45b422cf1804df06d5abb2ceda5ed65268a92135" - integrity sha512-uDvd4zxNGNYFE0TF4h7tAg+eMIPatyd1QdkP8fA4UYwshF4/+UwS1wegjXLEWQRRH87+UAyvx4IKQjobzzEX0A== - dependencies: - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-core-js@2.8.4": version "2.8.4" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" @@ -57,45 +28,11 @@ "@microsoft/applicationinsights-shims" "2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-dependencies-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-2.8.4.tgz#b9afbb81fb44aeb3033ecff1d2e4d33d71c1d41c" - integrity sha512-dr11EBFBR+vmtTipubZv9KSWRXLk6XdutkEgilgzXdSFun0dqR+ZSHEmMWyqE8ZsJtW+1HzdKuGtODSQY6uHyw== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-properties-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-2.8.4.tgz#c52a6ce03b8f99b2110a097b4ef30686dfb433f8" - integrity sha512-UI0afK5e8yUJ1qIdy+7FA/G9TB+st0++trx4bUMa+Hb6gJggdQPq94lBFJL0yzo4QsgQwozVwkInXy4534tTYQ== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== -"@microsoft/applicationinsights-web@^2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web/-/applicationinsights-web-2.8.4.tgz#6b385d385790b9574dad0754b860e656cde470b7" - integrity sha512-3CtZiM6e5Q0AA+1NE4k8A0+Y0FE1jsK4u0sb4AkvV7b4cwb86I9l7F7fQPU+V/ltkni0g2WtDrMNU93RuxSmNw== - dependencies: - "@microsoft/applicationinsights-analytics-js" "2.8.4" - "@microsoft/applicationinsights-channel-js" "2.8.4" - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-dependencies-js" "2.8.4" - "@microsoft/applicationinsights-properties-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/dynamicproto-js@^1.1.6": version "1.1.6" resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" @@ -131,22 +68,27 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== -xterm-addon-search@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0.tgz#95278ebb818cfcf882209ae75be96e0bea5d52a5" - integrity sha512-aoolI8YuHvdGw+Qjg8g2M4kst0v86GtB7WeBm4F0jNXA005/6QbWWy9eCsvnIDLJOFI5JSSrZnD6CaOkvBQYPA== +xterm-addon-canvas@0.2.0-beta.23: + version "0.2.0-beta.23" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.2.0-beta.23.tgz#f5ee0db3b029ea705ef3c1228825c28ec6368b48" + integrity sha512-414qLxMlOzC3LyAt1qHmvrcW2VIPAsFQkXTGcSzX42XCOTF4lA9Jf8ePVNgokQAyvlGK3j3K0y0d7lTTR5I/Zw== -xterm-addon-unicode11@0.4.0-beta.3: - version "0.4.0-beta.3" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" - integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== +xterm-addon-search@0.10.0-beta.6: + version "0.10.0-beta.6" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.6.tgz#a475d793a13b378f56b439b8c7eeeff2095831ae" + integrity sha512-fDS0dbM/ZuVBfieWyXJgFvQwNk95rpVbaBRcVpUM9sM/R5+ePQr+uhcaicfuWAku7urP7P/QNnkeAkeQjf8E6w== -xterm-addon-webgl@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0.tgz#2fba8d31890a122adafa1c2fb945482e2ae12973" - integrity sha512-3P5ihdjPnxH6Wrvqjki9UD+duoVrp1fvnO/pSpXP2F1L2GwY6TDNExgj8Yg141vMCNgQbcVqmsTLYEYZxjY92A== +xterm-addon-unicode11@0.4.0-beta.5: + version "0.4.0-beta.5" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.5.tgz#3900e66f10d2e506133b61d7421aab6878d32665" + integrity sha512-+g+fuxAd/tkCEJ/jhdnebXKtdPrhsu4VKWNnB/3qM35GbuGQOasmYFYnKL+HYZMpbQ6YqeZcXTVg/wnCTttz0g== -xterm@4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d" - integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ== +xterm-addon-webgl@0.13.0-beta.49: + version "0.13.0-beta.49" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.49.tgz#0cbffccccec06f5638ddc793ae7a0ff8ce0a891b" + integrity sha512-c1/8hLrw3PuPAnyPVLNg8i2FDkyu5SkU654DPEEgKgHHeAh3sfil28LleBpPhpP24531i7XNt1LLHCGMJ+gkFw== + +xterm@5.0.0-beta.54: + version "5.0.0-beta.54" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.0.0-beta.54.tgz#2c353221f289af22327aae6318bc6422c636fd41" + integrity sha512-wRzs1NbVCkZUzAqvglQcDVreT7RLLFkpdBi0oOLbZXgTaYr/Be93aCuuEjOVp7lnV0hi1gEP5K9Ugn621QffNw== diff --git a/remote/yarn.lock b/remote/yarn.lock index 8efe31b7992..0ac2187f123 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -20,35 +20,6 @@ "@microsoft/applicationinsights-shims" "^2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-analytics-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-2.8.4.tgz#3b32d8a2122be5d5993c74ef3217ebbf4876ea69" - integrity sha512-n/FPs8SS6rB8h+u157fiRh0TwUWKctxGNvr4M+LKeSdgDvf9c759gUeMR7r8xF6kBBfgkbmyaVORjsA1WJsU4g== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-channel-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-2.8.4.tgz#6de7210d87e61c72d3a9a06cbaeae14e1b543484" - integrity sha512-aml49Jya8LxX4tvyBbIvcxSo7UGI0k3HeiJQRFLeO+QlA+Ocsl10PqphU/OYJ4hh/P5/2QhEAq5bBM/b9/PNrg== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-common@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-common/-/applicationinsights-common-2.8.4.tgz#45b422cf1804df06d5abb2ceda5ed65268a92135" - integrity sha512-uDvd4zxNGNYFE0TF4h7tAg+eMIPatyd1QdkP8fA4UYwshF4/+UwS1wegjXLEWQRRH87+UAyvx4IKQjobzzEX0A== - dependencies: - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-core-js@2.8.4": version "2.8.4" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" @@ -57,45 +28,11 @@ "@microsoft/applicationinsights-shims" "2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-dependencies-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-2.8.4.tgz#b9afbb81fb44aeb3033ecff1d2e4d33d71c1d41c" - integrity sha512-dr11EBFBR+vmtTipubZv9KSWRXLk6XdutkEgilgzXdSFun0dqR+ZSHEmMWyqE8ZsJtW+1HzdKuGtODSQY6uHyw== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-properties-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-2.8.4.tgz#c52a6ce03b8f99b2110a097b4ef30686dfb433f8" - integrity sha512-UI0afK5e8yUJ1qIdy+7FA/G9TB+st0++trx4bUMa+Hb6gJggdQPq94lBFJL0yzo4QsgQwozVwkInXy4534tTYQ== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== -"@microsoft/applicationinsights-web@^2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web/-/applicationinsights-web-2.8.4.tgz#6b385d385790b9574dad0754b860e656cde470b7" - integrity sha512-3CtZiM6e5Q0AA+1NE4k8A0+Y0FE1jsK4u0sb4AkvV7b4cwb86I9l7F7fQPU+V/ltkni0g2WtDrMNU93RuxSmNw== - dependencies: - "@microsoft/applicationinsights-analytics-js" "2.8.4" - "@microsoft/applicationinsights-channel-js" "2.8.4" - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-dependencies-js" "2.8.4" - "@microsoft/applicationinsights-properties-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/dynamicproto-js@^1.1.6": version "1.1.6" resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" @@ -168,16 +105,6 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -applicationinsights@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.4.2.tgz#2f25f7a3f3e5bf0ab4486b63e42a48a9ec321d52" - integrity sha512-1wE37G9zEMZTsPJVQ8BDrQtsGgG3DGMActLHwPAF8TYHAXkfqqpeZYCH0XV4lUZ7H4MffRMwN2Ln2nEtUmT8HQ== - dependencies: - cls-hooked "^4.2.2" - continuation-local-storage "^3.2.1" - diagnostic-channel "0.2.0" - diagnostic-channel-publishers "^0.3.3" - aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -191,21 +118,6 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" -async-hook-jl@^1.7.6: - version "1.7.6" - resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" - integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== - dependencies: - stack-chain "^1.3.7" - -async-listener@^0.6.0: - version "0.6.10" - resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc" - integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw== - dependencies: - semver "^5.3.0" - shimmer "^1.1.0" - base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -245,15 +157,6 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== -cls-hooked@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" - integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== - dependencies: - async-hook-jl "^1.7.6" - emitter-listener "^1.0.1" - semver "^5.4.1" - 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" @@ -264,14 +167,6 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -continuation-local-storage@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb" - integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA== - dependencies: - async-listener "^0.6.0" - emitter-listener "^1.1.1" - cookie@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" @@ -325,25 +220,6 @@ detect-libc@^2.0.0: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== -diagnostic-channel-publishers@^0.3.3: - version "0.3.5" - resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.5.tgz#a84a05fd6cc1d7619fdd17791c17e540119a7536" - integrity sha512-AOIjw4T7Nxl0G2BoBPhkQ6i7T4bUd9+xvdYizwvG7vVAM1dvr+SDrcUudlmzwH0kbEwdR2V1EcnKT0wAeYLQNQ== - -diagnostic-channel@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17" - integrity sha512-awkcaaNNi0RfUGJf7r2+K4oJs1OyiIG2m/Jwvyi0OeQxdw+UU/iwbiejTPa3tUeyXtBcp2fef0JOJNdD62r/zg== - dependencies: - semver "^5.3.0" - -emitter-listener@^1.0.1, emitter-listener@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -706,16 +582,6 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -semver@^5.3.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== - -semver@^5.4.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" @@ -728,11 +594,6 @@ set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -shimmer@^1.1.0, shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - signal-exit@^3.0.0: version "3.0.6" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" @@ -783,11 +644,6 @@ spdlog@^0.13.0: mkdirp "^0.5.5" nan "^2.14.0" -stack-chain@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= - string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -932,35 +788,40 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-search@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0.tgz#95278ebb818cfcf882209ae75be96e0bea5d52a5" - integrity sha512-aoolI8YuHvdGw+Qjg8g2M4kst0v86GtB7WeBm4F0jNXA005/6QbWWy9eCsvnIDLJOFI5JSSrZnD6CaOkvBQYPA== +xterm-addon-canvas@0.2.0-beta.23: + version "0.2.0-beta.23" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.2.0-beta.23.tgz#f5ee0db3b029ea705ef3c1228825c28ec6368b48" + integrity sha512-414qLxMlOzC3LyAt1qHmvrcW2VIPAsFQkXTGcSzX42XCOTF4lA9Jf8ePVNgokQAyvlGK3j3K0y0d7lTTR5I/Zw== -xterm-addon-serialize@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0.tgz#cc7ef78972c8425b81dd6ae0a76824ce033d1e5f" - integrity sha512-ZfZ4Zj4uTEBFnUA0exipDGZ14jfiWLCov7gIt2OwIjQEz2ey8ic5kL/cxYz5antNz8/hTSA2qZcyA6VyyQASOQ== +xterm-addon-search@0.10.0-beta.6: + version "0.10.0-beta.6" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.6.tgz#a475d793a13b378f56b439b8c7eeeff2095831ae" + integrity sha512-fDS0dbM/ZuVBfieWyXJgFvQwNk95rpVbaBRcVpUM9sM/R5+ePQr+uhcaicfuWAku7urP7P/QNnkeAkeQjf8E6w== -xterm-addon-unicode11@0.4.0-beta.3: - version "0.4.0-beta.3" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" - integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== +xterm-addon-serialize@0.8.0-beta.6: + version "0.8.0-beta.6" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.8.0-beta.6.tgz#fe21a74a0ca3ecdf12843136115f074a431b3876" + integrity sha512-hb3TRqvg36MW5H4ZnYjw4EHb55iZ4rOOuH+Hx4ZTBDI1pszPtryFqXbS93NBLKgsOqDovIDsH8fWvNfhPdGmsQ== -xterm-addon-webgl@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0.tgz#2fba8d31890a122adafa1c2fb945482e2ae12973" - integrity sha512-3P5ihdjPnxH6Wrvqjki9UD+duoVrp1fvnO/pSpXP2F1L2GwY6TDNExgj8Yg141vMCNgQbcVqmsTLYEYZxjY92A== +xterm-addon-unicode11@0.4.0-beta.5: + version "0.4.0-beta.5" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.5.tgz#3900e66f10d2e506133b61d7421aab6878d32665" + integrity sha512-+g+fuxAd/tkCEJ/jhdnebXKtdPrhsu4VKWNnB/3qM35GbuGQOasmYFYnKL+HYZMpbQ6YqeZcXTVg/wnCTttz0g== -xterm-headless@4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0.tgz#965eb293fe6258adff5888f24e2a0b778b765e17" - integrity sha512-rYP8I1AGwaztpCoWe9mwxNqmfz7zZCjbzw61QChFqPeiDERjW9CDnqyGhSElvicHAlf47dvA+p4qOuKltxWEkg== +xterm-addon-webgl@0.13.0-beta.49: + version "0.13.0-beta.49" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.49.tgz#0cbffccccec06f5638ddc793ae7a0ff8ce0a891b" + integrity sha512-c1/8hLrw3PuPAnyPVLNg8i2FDkyu5SkU654DPEEgKgHHeAh3sfil28LleBpPhpP24531i7XNt1LLHCGMJ+gkFw== -xterm@4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d" - integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ== +xterm-headless@5.0.0-beta.5: + version "5.0.0-beta.5" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.0.0-beta.5.tgz#e29b6c5081f31f887122b7263ba996b0c46b3c22" + integrity sha512-CMQ1+prBNF92oBMeZzc2rfTcmOaCGfwwSaoPYNTjyziZT6mZsEg7amajYkb0YAnqJ29MFm4kPGZbU78/dX4k2A== + +xterm@5.0.0-beta.54: + version "5.0.0-beta.54" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.0.0-beta.54.tgz#2c353221f289af22327aae6318bc6422c636fd41" + integrity sha512-wRzs1NbVCkZUzAqvglQcDVreT7RLLFkpdBi0oOLbZXgTaYr/Be93aCuuEjOVp7lnV0hi1gEP5K9Ugn621QffNw== yallist@^4.0.0: version "4.0.0" diff --git a/resources/linux/debian/control.template b/resources/linux/debian/control.template index bfe0aa52da2..1a5981bb219 100644 --- a/resources/linux/debian/control.template +++ b/resources/linux/debian/control.template @@ -1,7 +1,8 @@ Package: @@NAME@@ Version: @@VERSION@@ Section: devel -Depends: libnss3 (>= 2:3.26), gnupg, apt, libxkbfile1, libsecret-1-0, libgtk-3-0 (>= 3.10.0), libxss1, libgbm1 +Depends: @@DEPENDS@@ +Recommends: @@RECOMMENDS@@ Priority: optional Architecture: @@ARCHITECTURE@@ Maintainer: Microsoft Corporation diff --git a/resources/linux/rpm/code.spec.template b/resources/linux/rpm/code.spec.template index 7eea9ff555d..61659d25837 100644 --- a/resources/linux/rpm/code.spec.template +++ b/resources/linux/rpm/code.spec.template @@ -11,7 +11,7 @@ Icon: @@NAME@@.xpm Requires: @@DEPENDENCIES@@ AutoReq: 0 -%global __provides_exclude_from ^%{_datadir}/@@NAME@@/.*\\.so.*$ +%global __provides_exclude_from ^%{_datadir}/%{name}/.*\\.so.*$ %description Visual Studio Code is a new choice of tool that combines the simplicity of a code editor with what developers need for the core edit-build-debug cycle. See https://code.visualstudio.com/docs/setup/linux for installation instructions and FAQ. @@ -21,29 +21,32 @@ Visual Studio Code is a new choice of tool that combines the simplicity of a cod %define _build_id_links none %install -mkdir -p %{buildroot}/usr/share/@@NAME@@ -mkdir -p %{buildroot}/usr/share/applications -mkdir -p %{buildroot}/usr/share/pixmaps -mkdir -p %{buildroot}/usr/share/bash-completion/completions -mkdir -p %{buildroot}/usr/share/zsh/site-functions -mkdir -p %{buildroot}/usr/share/mime/packages -cp -r usr/share/@@NAME@@/* %{buildroot}/usr/share/@@NAME@@ -cp -r usr/share/applications/@@NAME@@.desktop %{buildroot}/usr/share/applications -cp -r usr/share/applications/@@NAME@@-url-handler.desktop %{buildroot}/usr/share/applications -cp -r usr/share/mime/packages/@@NAME@@-workspace.xml %{buildroot}/usr/share/mime/packages/@@NAME@@-workspace.xml -cp -r usr/share/pixmaps/@@ICON@@.png %{buildroot}/usr/share/pixmaps -cp usr/share/bash-completion/completions/@@NAME@@ %{buildroot}/usr/share/bash-completion/completions/@@NAME@@ -cp usr/share/zsh/site-functions/_@@NAME@@ %{buildroot}/usr/share/zsh/site-functions/_@@NAME@@ +# Destination directories +mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}%{_datadir}/%{name} +mkdir -p %{buildroot}%{_datadir}/applications +mkdir -p %{buildroot}%{_datadir}/mime/packages +mkdir -p %{buildroot}%{_datadir}/pixmaps +mkdir -p %{buildroot}%{_datadir}/bash-completion/completions +mkdir -p %{buildroot}%{_datadir}/zsh/site-functions +# Application +cp -r usr/share/%{name}/* %{buildroot}%{_datadir}/%{name} +ln -s %{_datadir}/%{name}/bin/%{name} %{buildroot}%{_bindir}/%{name} +# Support files +cp -r usr/share/applications/%{name}.desktop %{buildroot}%{_datadir}/applications +cp -r usr/share/applications/%{name}-url-handler.desktop %{buildroot}%{_datadir}/applications +cp -r usr/share/mime/packages/%{name}-workspace.xml %{buildroot}%{_datadir}/mime/packages/%{name}-workspace.xml +cp -r usr/share/pixmaps/@@ICON@@.png %{buildroot}%{_datadir}/pixmaps +# Shell completions +cp usr/share/bash-completion/completions/%{name} %{buildroot}%{_datadir}/bash-completion/completions/%{name} +cp usr/share/zsh/site-functions/_%{name} %{buildroot}%{_datadir}/zsh/site-functions/_%{name} %post # Remove the legacy bin command if this is the stable build -if [ "@@NAME@@" = "code" ]; then +if [ "%{name}" = "code" ]; then rm -f /usr/local/bin/code fi -# Symlink bin command to /usr/bin -ln -sf /usr/share/@@NAME@@/bin/@@NAME@@ %{_bindir}/@@NAME@@ - # Register yum repository # TODO: #229: Enable once the yum repository is signed #if [ "@@NAME@@" != "code-oss" ]; then @@ -55,24 +58,21 @@ ln -sf /usr/share/@@NAME@@/bin/@@NAME@@ %{_bindir}/@@NAME@@ #fi # Update mimetype database to pickup workspace mimetype -update-mime-database /usr/share/mime &> /dev/null || : +update-mime-database %{_datadir}/mime &> /dev/null || : %postun -if [ $1 = 0 ]; then - rm -f /usr/bin/@@NAME@@ -fi - # Update mimetype database for removed workspace mimetype -update-mime-database /usr/share/mime &> /dev/null || : +update-mime-database %{_datadir}/mime &> /dev/null || : %files %defattr(-,root,root) -%attr(4755, root, root) /usr/share/@@NAME@@/chrome-sandbox +%attr(4755, root, root) %{_datadir}/%{name}/chrome-sandbox -/usr/share/@@NAME@@/ -/usr/share/applications/@@NAME@@.desktop -/usr/share/applications/@@NAME@@-url-handler.desktop -/usr/share/mime/packages/@@NAME@@-workspace.xml -/usr/share/pixmaps/@@ICON@@.png -/usr/share/bash-completion/completions/@@NAME@@ -/usr/share/zsh/site-functions/_@@NAME@@ +%{_bindir}/%{name} +%{_datadir}/%{name}/ +%{_datadir}/applications/%{name}.desktop +%{_datadir}/applications/%{name}-url-handler.desktop +%{_datadir}/mime/packages/%{name}-workspace.xml +%{_datadir}/pixmaps/@@ICON@@.png +%{_datadir}/bash-completion/completions/%{name} +%{_datadir}/zsh/site-functions/_%{name} diff --git a/resources/linux/snap/snapcraft.yaml b/resources/linux/snap/snapcraft.yaml index 8bbad497ace..fc775b6554f 100644 --- a/resources/linux/snap/snapcraft.yaml +++ b/resources/linux/snap/snapcraft.yaml @@ -58,11 +58,9 @@ apps: command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ --no-sandbox common-id: @@NAME@@.desktop environment: - DISABLE_WAYLAND: 1 GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas url-handler: command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ --open-url --no-sandbox environment: - DISABLE_WAYLAND: 1 GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas diff --git a/scripts/update-xterm.js b/scripts/update-xterm.js index 70637a8493c..bc574935902 100644 --- a/scripts/update-xterm.js +++ b/scripts/update-xterm.js @@ -8,6 +8,7 @@ const path = require('path'); const moduleNames = [ 'xterm', + 'xterm-addon-canvas', 'xterm-addon-search', 'xterm-addon-unicode11', 'xterm-addon-webgl' @@ -30,7 +31,17 @@ function getLatestModuleVersion(moduleName) { if (err) { reject(err); } - const versions = JSON.parse(stdout); + let versions = JSON.parse(stdout); + // HACK: Some bad versions were published as v5 which cannot be unpublished, ignore these + if (moduleName === 'xterm-addon-canvas') { + versions = versions.filter(e => ![ + '0.12.0', + '5.0.0-beta.1', + '5.0.0-beta.2', + '5.0.0-beta.3', + '5.0.0-beta.4', + ].includes(e)); + } resolve(versions[versions.length - 1]); }); }); diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 79381017f50..61ca6dd8477 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -136,6 +136,7 @@ 'vscode-textmate': `${baseNodeModulesPath}/vscode-textmate/release/main.js`, 'vscode-oniguruma': `${baseNodeModulesPath}/vscode-oniguruma/release/main.js`, 'xterm': `${baseNodeModulesPath}/xterm/lib/xterm.js`, + 'xterm-addon-canvas': `${baseNodeModulesPath}/xterm-addon-canvas/lib/xterm-addon-canvas.js`, 'xterm-addon-search': `${baseNodeModulesPath}/xterm-addon-search/lib/xterm-addon-search.js`, 'xterm-addon-unicode11': `${baseNodeModulesPath}/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`, 'xterm-addon-webgl': `${baseNodeModulesPath}/xterm-addon-webgl/lib/xterm-addon-webgl.js`, @@ -150,7 +151,7 @@ // which has a fallback to using node.js `require` // (node.js enabled renderers only) if (!safeProcess.sandboxed) { - loaderConfig.amdModulesPattern = /(^vs\/)|(^vscode-textmate$)|(^vscode-oniguruma$)|(^xterm$)|(^xterm-addon-search$)|(^xterm-addon-unicode11$)|(^xterm-addon-webgl$)|(^@vscode\/iconv-lite-umd$)|(^jschardet$)|(^@vscode\/vscode-languagedetection$)|(^vscode-regexp-languagedetection$)|(^tas-client-umd$)/; + loaderConfig.amdModulesPattern = /(^vs\/)|(^vscode-textmate$)|(^vscode-oniguruma$)|(^xterm$)|(^xterm-addon-canvas$)|(^xterm-addon-search$)|(^xterm-addon-unicode11$)|(^xterm-addon-webgl$)|(^@vscode\/iconv-lite-umd$)|(^jschardet$)|(^@vscode\/vscode-languagedetection$)|(^vscode-regexp-languagedetection$)|(^tas-client-umd$)/; } // Signal before require.config() diff --git a/src/bootstrap.js b/src/bootstrap.js index 319ddba9b02..1482973371c 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -205,7 +205,7 @@ } /** - * @returns {import('./vs/base/parts/sandbox/electron-sandbox/globals').ISandboxNodeProcess | NodeJS.Process} + * @returns {import('./vs/base/parts/sandbox/electron-sandbox/globals').ISandboxNodeProcess | NodeJS.Process | undefined} */ function safeProcess() { const sandboxGlobals = safeSandboxGlobals(); @@ -269,28 +269,8 @@ //#endregion - - //#region ApplicationInsights - - // Prevents appinsights from monkey patching modules. - // This should be called before importing the applicationinsights module - function avoidMonkeyPatchFromAppInsights() { - if (typeof process === 'undefined') { - console.warn('avoidMonkeyPatchFromAppInsights() is only available in node.js environments'); - return; - } - - // @ts-ignore - process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'] = true; // Skip monkey patching of 3rd party modules by appinsights - global['diagnosticsSource'] = {}; // Prevents diagnostic channel (which patches "require") from initializing entirely - } - - //#endregion - - return { enableASARSupport, - avoidMonkeyPatchFromAppInsights, setupNLS, fileUriFromPath }; diff --git a/src/cli.js b/src/cli.js index 398b4c09810..dd5ea5351ec 100644 --- a/src/cli.js +++ b/src/cli.js @@ -18,9 +18,6 @@ const bootstrap = require('./bootstrap'); const bootstrapNode = require('./bootstrap-node'); const product = require('../product.json'); -// Avoid Monkey Patches from Application Insights -bootstrap.avoidMonkeyPatchFromAppInsights(); - // Enable portable support bootstrapNode.configurePortable(product); diff --git a/src/main.js b/src/main.js index 47f22e9909f..73fe1be2ade 100644 --- a/src/main.js +++ b/src/main.js @@ -24,7 +24,7 @@ const { getUserDataPath } = require('./vs/platform/environment/node/userDataPath const { stripComments } = require('./vs/base/common/stripComments'); /** @type {Partial} */ const product = require('../product.json'); -const { app, protocol, crashReporter } = require('electron'); +const { app, protocol, crashReporter, Menu } = require('electron'); // Enable portable support const portable = bootstrapNode.configurePortable(product); @@ -43,6 +43,9 @@ const codeCachePath = getCodeCachePath(); // Configure static command line arguments const argvConfig = configureCommandlineSwitchesSync(args); +// Disable default menu (https://github.com/electron/electron/issues/35512) +Menu.setApplicationMenu(null); + // Configure crash reporter perf.mark('code/willStartCrashReporter'); // If a crash-reporter-directory is specified we store the crash reports @@ -153,9 +156,6 @@ function configureCommandlineSwitchesSync(cliArgs) { // alias from us for --disable-gpu 'disable-hardware-acceleration', - // provided by Electron - 'disable-color-correct-rendering', - // override for the color profile to use 'force-color-profile' ]; @@ -221,6 +221,12 @@ function configureCommandlineSwitchesSync(cliArgs) { } }); + /* Following features are disabled from the runtime. + * `CalculateNativeWinOcclusion` - Disable native window occlusion tracker, + * Refs https://groups.google.com/a/chromium.org/g/embedder-dev/c/ZF3uHHyWLKw/m/VDN2hDXMAAAJ + */ + app.commandLine.appendSwitch('disable-features', 'CalculateNativeWinOcclusion'); + // Support JS Flags const jsFlags = getJSFlags(cliArgs); if (jsFlags) { @@ -247,9 +253,7 @@ function readArgvConfigSync() { // 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) - }; + argvConfig = {}; } return argvConfig; @@ -279,11 +283,7 @@ function createDefaultArgvConfigSync(argvConfigPath) { '{', ' // 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', + ' // "disable-hardware-acceleration": true', '}' ]; @@ -393,7 +393,7 @@ function configureCrashReporter() { // Start crash reporter for all processes const productName = (product.crashReporter ? product.crashReporter.productName : undefined) || product.nameShort; const companyName = (product.crashReporter ? product.crashReporter.companyName : undefined) || 'Microsoft'; - const uploadToServer = !process.env['VSCODE_DEV'] && submitURL && !crashReporterDirectory; + const uploadToServer = Boolean(!process.env['VSCODE_DEV'] && submitURL && !crashReporterDirectory); crashReporter.start({ companyName, productName: process.env['VSCODE_DEV'] ? `${productName} Dev` : productName, @@ -416,7 +416,7 @@ function getJSFlags(cliArgs) { } // Support max-memory flag - if (cliArgs['max-memory'] && !/max_old_space_size=(\d+)/g.exec(cliArgs['js-flags'])) { + if (cliArgs['max-memory'] && !/max_old_space_size=(\d+)/g.exec(cliArgs['js-flags'] ?? '')) { jsFlags.push(`--max_old_space_size=${cliArgs['max-memory']}`); } diff --git a/src/tsconfig.base.json b/src/tsconfig.base.json index 18f99a6b7fe..a309a50adaa 100644 --- a/src/tsconfig.base.json +++ b/src/tsconfig.base.json @@ -37,6 +37,9 @@ "ES2020.String", "ES2020.Symbol.WellKnown", "ES2020.Intl", + "ES2021.Promise", + "ES2021.String", + "ES2021.WeakRef", "DOM", "DOM.Iterable", "WebWorker.ImportScripts" diff --git a/src/tsconfig.json b/src/tsconfig.json index eaaa3fb52b8..10ead1ecb06 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -5,7 +5,7 @@ "preserveConstEnums": true, "sourceMap": false, "outDir": "../out/vs", - "target": "es2020", + "target": "es2021", "types": [ "keytar", "mocha", diff --git a/src/tsec.exemptions.json b/src/tsec.exemptions.json index d5ce3f010a9..9902ab953e7 100644 --- a/src/tsec.exemptions.json +++ b/src/tsec.exemptions.json @@ -7,7 +7,7 @@ "vs/workbench/api/worker/extHostExtensionService.ts", "vs/base/worker/workerMain", "vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts", - "vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts" + "vs/workbench/services/keybinding/test/node/keyboardMapperTestUtils.ts" ], "ban-trustedtypes-createpolicy": [ "vs/base/browser/dom.ts", @@ -15,6 +15,7 @@ "vs/base/browser/defaultWorkerFactory.ts", "vs/base/worker/workerMain.ts", "vs/editor/contrib/markdownRenderer/browser/markdownRenderer.ts", + "vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts", "vs/editor/browser/view/domLineBreaksComputer.ts", "vs/editor/browser/view/viewLayer.ts", "vs/editor/browser/widget/diffEditorWidget.ts", diff --git a/src/vs/base/browser/broadcast.ts b/src/vs/base/browser/broadcast.ts new file mode 100644 index 00000000000..d7785f42ff8 --- /dev/null +++ b/src/vs/base/browser/broadcast.ts @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { getErrorMessage } from 'vs/base/common/errors'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; + +export class BroadcastDataChannel extends Disposable { + + private broadcastChannel: BroadcastChannel | undefined; + + private readonly _onDidReceiveData = this._register(new Emitter()); + readonly onDidReceiveData = this._onDidReceiveData.event; + + constructor(private readonly channelName: string) { + super(); + + // Use BroadcastChannel + if ('BroadcastChannel' in window) { + try { + this.broadcastChannel = new BroadcastChannel(channelName); + const listener = (event: MessageEvent) => { + this._onDidReceiveData.fire(event.data); + }; + this.broadcastChannel.addEventListener('message', listener); + this._register(toDisposable(() => { + if (this.broadcastChannel) { + this.broadcastChannel.removeEventListener('message', listener); + this.broadcastChannel.close(); + } + })); + } catch (error) { + console.warn('Error while creating broadcast channel. Falling back to localStorage.', getErrorMessage(error)); + } + } + + // BroadcastChannel is not supported. Use storage. + if (!this.broadcastChannel) { + this.channelName = `BroadcastDataChannel.${channelName}`; + this.createBroadcastChannel(); + } + } + + private createBroadcastChannel(): void { + const listener = (event: StorageEvent) => { + if (event.key === this.channelName && event.newValue) { + this._onDidReceiveData.fire(JSON.parse(event.newValue)); + } + }; + window.addEventListener('storage', listener); + this._register(toDisposable(() => window.removeEventListener('storage', listener))); + } + + /** + * Sends the data to other BroadcastChannel objects set up for this channel. Data can be structured objects, e.g. nested objects and arrays. + * @param data data to broadcast + */ + postData(data: T): void { + if (this.broadcastChannel) { + this.broadcastChannel.postMessage(data); + } else { + // remove previous changes so that event is triggered even if new changes are same as old changes + window.localStorage.removeItem(this.channelName); + window.localStorage.setItem(this.channelName, JSON.stringify(data)); + } + } +} diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 8191f523595..01db9eebc27 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -194,9 +194,16 @@ export const isAndroid = (userAgent.indexOf('Android') >= 0); let standalone = false; if (window.matchMedia) { - const matchMedia = window.matchMedia('(display-mode: standalone)'); - standalone = matchMedia.matches; - addMatchMediaChangeListener(matchMedia, ({ matches }) => { + const standaloneMatchMedia = window.matchMedia('(display-mode: standalone)'); + const fullScreenMatchMedia = window.matchMedia('(display-mode: fullscreen)'); + standalone = standaloneMatchMedia.matches; + addMatchMediaChangeListener(standaloneMatchMedia, ({ matches }) => { + // entering fullscreen would change standaloneMatchMedia.matches to false + // if standalone is true (running as PWA) and entering fullscreen, skip this change + if (standalone && fullScreenMatchMedia.matches) { + return; + } + // otherwise update standalone (browser to PWA or PWA to browser) standalone = matches; }); } diff --git a/src/vs/base/browser/defaultWorkerFactory.ts b/src/vs/base/browser/defaultWorkerFactory.ts index c57e67f3698..9d2a34494be 100644 --- a/src/vs/base/browser/defaultWorkerFactory.ts +++ b/src/vs/base/browser/defaultWorkerFactory.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { COI } from 'vs/base/common/network'; import { globals } from 'vs/base/common/platform'; import { IWorker, IWorkerCallback, IWorkerFactory, logOnceWebWorkerWarning } from 'vs/base/common/worker/simpleWorker'; @@ -41,7 +42,12 @@ export function getWorkerBootstrapUrl(scriptPath: string, label: string): string const blob = new Blob([js], { type: 'application/javascript' }); return URL.createObjectURL(blob); } - return scriptPath + '#' + label; + + const result = new URL(scriptPath); + COI.addSearchParam(result.searchParams, true, true); + result.hash = label; + return result.href; + } // ESM-comment-end diff --git a/src/vs/base/browser/dnd.ts b/src/vs/base/browser/dnd.ts index e1a0872271a..8b557e01bef 100644 --- a/src/vs/base/browser/dnd.ts +++ b/src/vs/base/browser/dnd.ts @@ -92,24 +92,3 @@ export interface IDragAndDropData { update(dataTransfer: DataTransfer): void; getData(): unknown; } - -export class DragAndDropData implements IDragAndDropData { - - constructor(private data: T) { } - - update(): void { - // noop - } - - getData(): T { - return this.data; - } -} - -export interface IStaticDND { - CurrentDragAndDropData: IDragAndDropData | undefined; -} - -export const StaticDND: IStaticDND = { - CurrentDragAndDropData: undefined -}; diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 4d08566a4f6..5d7791363a3 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -123,24 +123,6 @@ export function addDisposableGenericMouseUpListener(node: EventTarget, handler: return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_UP : EventType.MOUSE_UP, handler, useCapture); } -export function createEventEmitter(target: HTMLElement, type: K, options?: boolean | AddEventListenerOptions): event.Emitter { - let domListener: DomListener | null = null; - const handler = (e: HTMLElementEventMap[K]) => result.fire(e); - const onFirstListenerAdd = () => { - if (!domListener) { - domListener = new DomListener(target, type, handler, options); - } - }; - const onLastListenerRemove = () => { - if (domListener) { - domListener.dispose(); - domListener = null; - } - }; - const result = new event.Emitter({ onFirstListenerAdd, onLastListenerRemove }); - return result; -} - interface IRequestAnimationFrame { (callback: (time: number) => void): number; } @@ -363,16 +345,8 @@ class SizeUtils { } private static getDimension(element: HTMLElement, cssPropertyName: string, jsPropertyName: string): number { - const computedStyle: CSSStyleDeclaration = getComputedStyle(element); - let value = '0'; - if (computedStyle) { - if (computedStyle.getPropertyValue) { - value = computedStyle.getPropertyValue(cssPropertyName); - } else { - // IE8 - value = (computedStyle).getAttribute(jsPropertyName); - } - } + const computedStyle = getComputedStyle(element); + const value = computedStyle ? computedStyle.getPropertyValue(cssPropertyName) : '0'; return SizeUtils.convertToPixels(element, value); } @@ -541,8 +515,8 @@ export function position(element: HTMLElement, top: number, right?: number, bott export function getDomNodePagePosition(domNode: HTMLElement): IDomNodePagePosition { const bb = domNode.getBoundingClientRect(); return { - left: bb.left + StandardWindow.scrollX, - top: bb.top + StandardWindow.scrollY, + left: bb.left + window.scrollX, + top: bb.top + window.scrollY, width: bb.width, height: bb.height }; @@ -566,30 +540,6 @@ export function getDomNodeZoomLevel(domNode: HTMLElement): number { return zoom; } -export interface IStandardWindow { - readonly scrollX: number; - readonly scrollY: number; -} - -export const StandardWindow: IStandardWindow = new class implements IStandardWindow { - get scrollX(): number { - if (typeof window.scrollX === 'number') { - // modern browsers - return window.scrollX; - } else { - return document.body.scrollLeft + document.documentElement!.scrollLeft; - } - } - - get scrollY(): number { - if (typeof window.scrollY === 'number') { - // modern browsers - return window.scrollY; - } else { - return document.body.scrollTop + document.documentElement!.scrollTop; - } - } -}; // Adapted from WinJS // Gets the width of the element, including margins. @@ -892,22 +842,12 @@ export interface EventLike { } export const EventHelper = { - stop: function (e: EventLike, cancelBubble?: boolean) { - if (e.preventDefault) { - e.preventDefault(); - } else { - // IE8 - (e).returnValue = false; - } - + stop: (e: T, cancelBubble?: boolean): T => { + e.preventDefault(); if (cancelBubble) { - if (e.stopPropagation) { - e.stopPropagation(); - } else { - // IE8 - (e).cancelBubble = true; - } + e.stopPropagation(); } + return e; } }; @@ -1149,18 +1089,12 @@ export function removeTabIndexAndUpdateFocus(node: HTMLElement): void { // in the hierarchy of the parent DOM nodes. if (document.activeElement === node) { const parentFocusable = findParentWithAttribute(node.parentElement, 'tabIndex'); - if (parentFocusable) { - parentFocusable.focus(); - } + parentFocusable?.focus(); } node.removeAttribute('tabindex'); } -export function getElementsByTagName(tag: string): HTMLElement[] { - return Array.prototype.slice.call(document.getElementsByTagName(tag), 0); -} - export function finalHandler(fn: (event: T) => any): (event: T) => any { return e => { e.preventDefault(); @@ -1734,50 +1668,87 @@ export function computeClippingRect(elementOrRect: HTMLElement | DOMRectReadOnly return { top, right, bottom, left }; } -interface DomNodeAttributes { - role?: string; - ariaHidden?: boolean; - style?: StyleAttributes; -} +type HTMLElementAttributeKeys = Partial<{ [K in keyof T]: T[K] extends Function ? never : T[K] extends object ? HTMLElementAttributeKeys : T[K] }>; +type ElementAttributes = HTMLElementAttributeKeys & Record; +type RemoveHTMLElement = T extends HTMLElement ? never : T; +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; +type ArrayToObj = UnionToIntersection>; +type HHTMLElementTagNameMap = HTMLElementTagNameMap & { '': HTMLDivElement }; -interface StyleAttributes { - height?: number | string; - width?: number | string; -} +type TagToElement = T extends `${infer TStart}#${string}` + ? TStart extends keyof HHTMLElementTagNameMap + ? HHTMLElementTagNameMap[TStart] + : HTMLElement + : T extends `${infer TStart}.${string}` + ? TStart extends keyof HHTMLElementTagNameMap + ? HHTMLElementTagNameMap[TStart] + : HTMLElement + : T extends keyof HTMLElementTagNameMap + ? HTMLElementTagNameMap[T] + : HTMLElement; -// +type TagToElementAndId = TTag extends `${infer TTag}@${infer TId}` + ? { element: TagToElement; id: TId } + : { element: TagToElement; id: 'root' }; + +type TagToRecord = TagToElementAndId extends { element: infer TElement; id: infer TId } + ? Record<(TId extends string ? TId : never) | 'root', TElement> + : never; + +type Child = HTMLElement | string | Record; +type Children = [] + | [Child] + | [Child, Child] + | [Child, Child, Child] + | [Child, Child, Child, Child] + | [Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child] + | [Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child, Child]; + +const H_REGEX = /(?[\w\-]+)?(?:#(?[\w\-]+))?(?(?:\.(?:[\w\-]+))*)(?:@(?(?:[\w\_])+))?/; /** * A helper function to create nested dom nodes. * * * ```ts - * private readonly htmlElements = h('div.code-view', [ - * h('div.title', { $: 'title' }), + * const elements = h('div.code-view', [ + * h('div.title@title'), * h('div.container', [ - * h('div.gutter', { $: 'gutterDiv' }), - * h('div', { $: 'editor' }), + * h('div.gutter@gutterDiv'), + * h('div@editor'), * ]), * ]); - * private readonly editor = createEditor(this.htmlElements.editor); + * const editor = createEditor(elements.editor); * ``` */ -export function h( - tag: TTag, - attributes: { $: TId } & DomNodeAttributes -): Record>; -export function h(tag: TTag, attributes: DomNodeAttributes): Record<'root', TagToElement>; -export function h)[]>( - tag: TTag, - children: T -): (ArrayToObj & Record<'root', TagToElement>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; -export function h)[]>( - tag: TTag, - attributes: { $: TId } & DomNodeAttributes, - children: T -): (ArrayToObj & Record>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; -export function h(tag: string, ...args: [] | [attributes: { $: string } & DomNodeAttributes | Record, children?: any[]] | [children: any[]]): Record { - let attributes: { $?: string } & DomNodeAttributes; +export function h + (tag: TTag): + TagToRecord extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; + +export function h + (tag: TTag, children: T): + (ArrayToObj & TagToRecord) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; + +export function h + (tag: TTag, attributes: Partial>>): + TagToRecord extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; + +export function h + (tag: TTag, attributes: Partial>>, children: T): + (ArrayToObj & TagToRecord) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; + +export function h(tag: string, ...args: [] | [attributes: { $: string } & Partial> | Record, children?: any[]] | [children: any[]]): Record { + let attributes: { $?: string } & Partial>; let children: (Record | HTMLElement)[] | undefined; if (Array.isArray(args[0])) { @@ -1788,14 +1759,29 @@ export function h(tag: string, ...args: [] | [attributes: { $: string } & DomNod children = args[1]; } - const [tagName, className] = tag.split('.'); + const match = H_REGEX.exec(tag); + + if (!match || !match.groups) { + throw new Error('Bad use of h'); + } + + const tagName = match.groups['tag'] || 'div'; const el = document.createElement(tagName); - if (className) { - el.className = className; + + if (match.groups['id']) { + el.id = match.groups['id']; + } + + if (match.groups['class']) { + el.className = match.groups['class'].replace(/\./g, ' ').trim(); } const result: Record = {}; + if (match.groups['name']) { + result[match.groups['name']] = el; + } + if (children) { for (const c of children) { if (c instanceof HTMLElement) { @@ -1810,10 +1796,6 @@ export function h(tag: string, ...args: [] | [attributes: { $: string } & DomNod } for (const [key, value] of Object.entries(attributes)) { - if (key === '$') { - result[value] = el; - continue; - } if (key === 'style') { for (const [cssKey, cssValue] of Object.entries(value)) { el.style.setProperty( @@ -1821,9 +1803,11 @@ export function h(tag: string, ...args: [] | [attributes: { $: string } & DomNod typeof cssValue === 'number' ? cssValue + 'px' : '' + cssValue ); } - continue; + } else if (key === 'tabIndex') { + el.tabIndex = value; + } else { + el.setAttribute(camelCaseToHyphenCase(key), value.toString()); } - el.setAttribute(camelCaseToHyphenCase(key), value.toString()); } result['root'] = el; @@ -1834,24 +1818,3 @@ export function h(tag: string, ...args: [] | [attributes: { $: string } & DomNod function camelCaseToHyphenCase(str: string) { return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); } - -type RemoveHTMLElement = T extends HTMLElement ? never : T; - -type ArrayToObj = UnionToIntersection>; - - -type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; - -type HTMLElementsByTagName = { - div: HTMLDivElement; - span: HTMLSpanElement; - a: HTMLAnchorElement; -}; - -type TagToElement = T extends `${infer TStart}.${string}` - ? TStart extends keyof HTMLElementsByTagName - ? HTMLElementsByTagName[TStart] - : HTMLElement - : T extends keyof HTMLElementsByTagName - ? HTMLElementsByTagName[T] - : HTMLElement; diff --git a/src/vs/base/browser/event.ts b/src/vs/base/browser/event.ts index adef057e119..600a5f78248 100644 --- a/src/vs/base/browser/event.ts +++ b/src/vs/base/browser/event.ts @@ -45,18 +45,3 @@ export class DomEmitter implements IDisposable { this.emitter.dispose(); } } - -export interface CancellableEvent { - preventDefault(): void; - stopPropagation(): void; -} - -export function stopEvent(event: T): T { - event.preventDefault(); - event.stopPropagation(); - return event; -} - -export function stop(event: BaseEvent): BaseEvent { - return BaseEvent.map(event, stopEvent); -} diff --git a/src/vs/base/browser/formattedTextRenderer.ts b/src/vs/base/browser/formattedTextRenderer.ts index daef833851a..2ae545682cd 100644 --- a/src/vs/base/browser/formattedTextRenderer.ts +++ b/src/vs/base/browser/formattedTextRenderer.ts @@ -8,7 +8,7 @@ import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { DisposableStore } from 'vs/base/common/lifecycle'; export interface IContentActionHandler { - callback: (content: string, event?: IMouseEvent) => void; + callback: (content: string, event: IMouseEvent) => void; readonly disposables: DisposableStore; } diff --git a/src/vs/base/browser/indexedDB.ts b/src/vs/base/browser/indexedDB.ts index 25651932124..5d985a1e571 100644 --- a/src/vs/base/browser/indexedDB.ts +++ b/src/vs/base/browser/indexedDB.ts @@ -6,7 +6,6 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import { getErrorMessage } from 'vs/base/common/errors'; import { mark } from 'vs/base/common/performance'; -import { isArray } from 'vs/base/common/types'; class MissingStoresError extends Error { constructor(readonly db: IDBDatabase) { @@ -106,9 +105,7 @@ export class IndexedDB { if (this.pendingTransactions.length) { this.pendingTransactions.splice(0, this.pendingTransactions.length).forEach(transaction => transaction.abort()); } - if (this.database) { - this.database.close(); - } + this.database?.close(); this.database = null; } @@ -122,7 +119,7 @@ export class IndexedDB { this.pendingTransactions.push(transaction); return new Promise((c, e) => { transaction.oncomplete = () => { - if (isArray(request)) { + if (Array.isArray(request)) { c(request.map(r => r.result)); } else { c(request.result); diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 2e809e2ad48..063d60b9792 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -9,13 +9,12 @@ import { DomEmitter } from 'vs/base/browser/event'; import { createElement, FormattedTextRenderOptions } from 'vs/base/browser/formattedTextRenderer'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; -import { raceCancellation } from 'vs/base/common/async'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Event } from 'vs/base/common/event'; import { IMarkdownString, escapeDoubleQuotes, parseHrefAndDimensions, removeMarkdownEscapes } from 'vs/base/common/htmlContent'; import { markdownEscapeEscapedIcons } from 'vs/base/common/iconLabels'; import { defaultGenerator } from 'vs/base/common/idGenerator'; +import { Lazy } from 'vs/base/common/lazy'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { marked } from 'vs/base/common/marked/marked'; import { parse } from 'vs/base/common/marshalling'; @@ -34,6 +33,53 @@ export interface MarkdownRenderOptions extends FormattedTextRenderOptions { readonly asyncRenderCallback?: () => void; } +const defaultMarkedRenderers = Object.freeze({ + image: (href: string | null, title: string | null, text: string): string => { + let dimensions: string[] = []; + let attributes: string[] = []; + if (href) { + ({ href, dimensions } = parseHrefAndDimensions(href)); + attributes.push(`src="${escapeDoubleQuotes(href)}"`); + } + if (text) { + attributes.push(`alt="${escapeDoubleQuotes(text)}"`); + } + if (title) { + attributes.push(`title="${escapeDoubleQuotes(title)}"`); + } + if (dimensions.length) { + attributes = attributes.concat(dimensions); + } + return ''; + }, + + paragraph: (text: string): string => { + return `

${text}

`; + }, + + link: (href: string | null, title: string | null, text: string): string => { + if (typeof href !== 'string') { + return ''; + } + + // Remove markdown escapes. Workaround for https://github.com/chjj/marked/issues/829 + if (href === text) { // raw link case + text = removeMarkdownEscapes(text); + } + + title = typeof title === 'string' ? escapeDoubleQuotes(removeMarkdownEscapes(title)) : ''; + href = removeMarkdownEscapes(href); + + // HTML Encode href + href = href.replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + return `${text}`; + }, +}); + /** * Low-level way create a html element from a markdown string. * @@ -44,8 +90,6 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende const disposables = new DisposableStore(); let isDisposed = false; - const cts = disposables.add(new CancellationTokenSource()); - const element = createElement(options); const _uriMassage = function (part: string): string { @@ -96,74 +140,19 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende return uri.toString(); }; - // signal to code-block render that the - // element has been created - let signalInnerHTML: () => void; - const withInnerHTML = new Promise(c => signalInnerHTML = c); - const renderer = new marked.Renderer(); + renderer.image = defaultMarkedRenderers.image; + renderer.link = defaultMarkedRenderers.link; + renderer.paragraph = defaultMarkedRenderers.paragraph; - renderer.image = (href: string, title: string, text: string) => { - let dimensions: string[] = []; - let attributes: string[] = []; - if (href) { - ({ href, dimensions } = parseHrefAndDimensions(href)); - attributes.push(`src="${escapeDoubleQuotes(href)}"`); - } - if (text) { - attributes.push(`alt="${escapeDoubleQuotes(text)}"`); - } - if (title) { - attributes.push(`title="${escapeDoubleQuotes(title)}"`); - } - if (dimensions.length) { - attributes = attributes.concat(dimensions); - } - return ''; - }; - renderer.link = (href, title, text): string => { - if (typeof href !== 'string') { - return ''; - } - - // Remove markdown escapes. Workaround for https://github.com/chjj/marked/issues/829 - if (href === text) { // raw link case - text = removeMarkdownEscapes(text); - } - - title = typeof title === 'string' ? escapeDoubleQuotes(removeMarkdownEscapes(title)) : ''; - href = removeMarkdownEscapes(href); - - // HTML Encode href - href = href.replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - return `${text}`; - }; - renderer.paragraph = (text): string => { - return `

${text}

`; - }; + // Will collect [id, renderedElement] tuples + const codeBlocks: Promise<[string, HTMLElement]>[] = []; if (options.codeBlockRenderer) { renderer.code = (code, lang) => { - const value = options.codeBlockRenderer!(lang ?? '', code); - // when code-block rendering is async we return sync - // but update the node with the real result later. const id = defaultGenerator.nextId(); - raceCancellation(Promise.all([value, withInnerHTML]), cts.token).then(values => { - if (!isDisposed && values) { - const span = element.querySelector(`div[data-code="${id}"]`); - if (span) { - DOM.reset(span, values[0]); - } - options.asyncRenderCallback?.(); - } - }).catch(() => { - // ignore - }); - + const value = options.codeBlockRenderer!(postProcessCodeBlockLanguageId(lang), code); + codeBlocks.push(value.then(element => [id, element])); return `
${escape(code)}
`; }; } @@ -277,8 +266,22 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende element.innerHTML = sanitizeRenderedMarkdown(markdown, markdownHtmlDoc.body.innerHTML) as unknown as string; - // signal that async code blocks can be now be inserted - signalInnerHTML!(); + if (codeBlocks.length > 0) { + Promise.all(codeBlocks).then((tuples) => { + if (isDisposed) { + return; + } + const renderedElements = new Map(tuples); + const placeholderElements = element.querySelectorAll(`div[data-code]`); + for (const placeholderElement of placeholderElements) { + const renderedElement = renderedElements.get(placeholderElement.dataset['code'] ?? ''); + if (renderedElement) { + DOM.reset(placeholderElement, renderedElement); + } + } + options.asyncRenderCallback?.(); + }); + } // signal size changes for image tags if (options.asyncRenderCallback) { @@ -294,12 +297,23 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende element, dispose: () => { isDisposed = true; - cts.cancel(); disposables.dispose(); } }; } +function postProcessCodeBlockLanguageId(lang: string | undefined): string { + if (!lang) { + return ''; + } + + const parts = lang.split(/[\s+|:|,|\{|\?]/, 1); + if (parts.length) { + return parts[0]; + } + return lang; +} + function resolveWithBaseUri(baseUri: URI, href: string): string { const hasScheme = /^\w[\w\d+.-]*:/.test(href); if (hasScheme) { @@ -386,6 +400,27 @@ export function renderStringAsPlaintext(string: IMarkdownString | string) { * Strips all markdown from `markdown`. For example `# Header` would be output as `Header`. */ export function renderMarkdownAsPlaintext(markdown: IMarkdownString) { + // values that are too long will freeze the UI + let value = markdown.value ?? ''; + if (value.length > 100_000) { + value = `${value.substr(0, 100_000)}…`; + } + + const html = marked.parse(value, { renderer: plainTextRenderer.getValue() }).replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m); + + return sanitizeRenderedMarkdown({ isTrusted: false }, html).toString(); +} + +const unescapeInfo = new Map([ + ['"', '"'], + [' ', ' '], + ['&', '&'], + [''', '\''], + ['<', '<'], + ['>', '>'], +]); + +const plainTextRenderer = new Lazy(() => { const renderer = new marked.Renderer(); renderer.code = (code: string): string => { @@ -448,22 +483,5 @@ export function renderMarkdownAsPlaintext(markdown: IMarkdownString) { renderer.link = (_href: string, _title: string, text: string): string => { return text; }; - // values that are too long will freeze the UI - let value = markdown.value ?? ''; - if (value.length > 100_000) { - value = `${value.substr(0, 100_000)}…`; - } - - const unescapeInfo = new Map([ - ['"', '"'], - [' ', ' '], - ['&', '&'], - [''', '\''], - ['<', '<'], - ['>', '>'], - ]); - - const html = marked.parse(value, { renderer }).replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m); - - return sanitizeRenderedMarkdown({ isTrusted: false }, html).toString(); -} + return renderer; +}); diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts index a4f106a6c19..e6f5d3b5a4b 100644 --- a/src/vs/base/browser/mouseEvent.ts +++ b/src/vs/base/browser/mouseEvent.ts @@ -88,28 +88,14 @@ export class StandardMouseEvent implements IMouseEvent { } } -export interface IDataTransfer { - dropEffect: string; - effectAllowed: string; - types: any[]; - files: any[]; - - setData(type: string, data: string): void; - setDragImage(image: any, x: number, y: number): void; - - getData(type: string): string; - clearData(types?: string[]): void; -} - export class DragMouseEvent extends StandardMouseEvent { - public readonly dataTransfer: IDataTransfer; + public readonly dataTransfer: DataTransfer; constructor(e: MouseEvent) { super(e); this.dataTransfer = (e).dataTransfer; } - } export interface IMouseWheelEvent extends MouseEvent { @@ -211,14 +197,10 @@ export class StandardWheelEvent { } public preventDefault(): void { - if (this.browserEvent) { - this.browserEvent.preventDefault(); - } + this.browserEvent?.preventDefault(); } public stopPropagation(): void { - if (this.browserEvent) { - this.browserEvent.stopPropagation(); - } + this.browserEvent?.stopPropagation(); } } diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index a41daab42af..0e97d180ef1 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -23,6 +23,7 @@ export interface IBaseActionViewItemOptions { draggable?: boolean; isMenu?: boolean; useEventAsContext?: boolean; + hoverDelegate?: IHoverDelegate; } export class BaseActionViewItem extends Disposable implements IActionViewItem { @@ -32,6 +33,8 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { _context: unknown; readonly _action: IAction; + private customHover?: ICustomHover; + get action() { return this._action; } @@ -92,10 +95,6 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { this._actionRunner = actionRunner; } - getAction(): IAction { - return this._action; - } - isEnabled(): boolean { return this._action.enabled; } @@ -210,8 +209,34 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { // implement in subclass } + protected getTooltip(): string | undefined { + return this.action.tooltip; + } + protected updateTooltip(): void { - // implement in subclass + if (!this.element) { + return; + } + const title = this.getTooltip() ?? ''; + this.updateAriaLabel(); + if (!this.options.hoverDelegate) { + this.element.title = title; + } else { + this.element.title = ''; + if (!this.customHover) { + this.customHover = setupCustomHover(this.options.hoverDelegate, this.element, title); + this._store.add(this.customHover); + } else { + this.customHover.update(title); + } + } + } + + protected updateAriaLabel(): void { + if (this.element) { + const title = this.getTooltip() ?? ''; + this.element.setAttribute('aria-label', title); + } } protected updateClass(): void { @@ -236,7 +261,6 @@ export interface IActionViewItemOptions extends IBaseActionViewItemOptions { icon?: boolean; label?: boolean; keybinding?: string | null; - hoverDelegate?: IHoverDelegate; } export class ActionViewItem extends BaseActionViewItem { @@ -245,7 +269,6 @@ export class ActionViewItem extends BaseActionViewItem { protected override options: IActionViewItemOptions; private cssClass?: string; - private customHover?: ICustomHover; constructor(context: unknown, action: IAction, options: IActionViewItemOptions = {}) { super(context, action, options); @@ -313,41 +336,24 @@ export class ActionViewItem extends BaseActionViewItem { override updateLabel(): void { if (this.options.label && this.label) { - this.label.textContent = this.getAction().label; + this.label.textContent = this.action.label; } } - override updateTooltip(): void { + override getTooltip() { let title: string | null = null; - if (this.getAction().tooltip) { - title = this.getAction().tooltip; + if (this.action.tooltip) { + title = this.action.tooltip; - } else if (!this.options.label && this.getAction().label && this.options.icon) { - title = this.getAction().label; + } else if (!this.options.label && this.action.label && this.options.icon) { + title = this.action.label; if (this.options.keybinding) { title = nls.localize({ key: 'titleLabel', comment: ['action title', 'action keybinding'] }, "{0} ({1})", title, this.options.keybinding); } } - this._applyUpdateTooltip(title); - } - - protected _applyUpdateTooltip(title: string | undefined | null): void { - if (title && this.label) { - this.label.setAttribute('aria-label', title); - if (!this.options.hoverDelegate) { - this.label.title = title; - } else { - this.label.title = ''; - if (!this.customHover) { - this.customHover = setupCustomHover(this.options.hoverDelegate, this.label, title); - this._store.add(this.customHover); - } else { - this.customHover.update(title); - } - } - } + return title ?? undefined; } override updateClass(): void { @@ -356,7 +362,7 @@ export class ActionViewItem extends BaseActionViewItem { } if (this.options.icon) { - this.cssClass = this.getAction().class; + this.cssClass = this.action.class; if (this.label) { this.label.classList.add('codicon'); @@ -372,7 +378,7 @@ export class ActionViewItem extends BaseActionViewItem { } override updateEnabled(): void { - if (this.getAction().enabled) { + if (this.action.enabled) { if (this.label) { this.label.removeAttribute('aria-disabled'); this.label.classList.remove('disabled'); @@ -389,9 +395,16 @@ export class ActionViewItem extends BaseActionViewItem { } } + override updateAriaLabel(): void { + if (this.label) { + const title = this.getTooltip() ?? ''; + this.label.setAttribute('aria-label', title); + } + } + override updateChecked(): void { if (this.label) { - if (this.getAction().checked) { + if (this.action.checked) { this.label.classList.add('checked'); } else { this.label.classList.remove('checked'); @@ -436,15 +449,11 @@ export class SelectActionViewItem extends BaseActionViewItem { } override focus(): void { - if (this.selectBox) { - this.selectBox.focus(); - } + this.selectBox?.focus(); } override blur(): void { - if (this.selectBox) { - this.selectBox.blur(); - } + this.selectBox?.blur(); } override render(container: HTMLElement): void { diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 4d210d5c16a..45e5f3800a3 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -46,6 +46,7 @@ } .monaco-action-bar .action-label { + display: flex; font-size: 11px; padding: 3px; border-radius: 5px; @@ -105,6 +106,12 @@ display: flex; } -.monaco-action-bar .action-item.action-dropdown-item > .action-label { - margin-right: 1px; +.monaco-action-bar .action-item.action-dropdown-item > .action-dropdown-item-separator { + display: flex; + align-items: center; + cursor: default; +} + +.monaco-action-bar .action-item.action-dropdown-item > .action-dropdown-item-separator > div { + width: 1px; } diff --git a/src/vs/base/browser/ui/button/button.css b/src/vs/base/browser/ui/button/button.css index ed4131eefd3..36beeb00478 100644 --- a/src/vs/base/browser/ui/button/button.css +++ b/src/vs/base/browser/ui/button/button.css @@ -8,6 +8,7 @@ display: flex; width: 100%; padding: 4px; + border-radius: 2px; text-align: center; cursor: pointer; justify-content: center; @@ -38,8 +39,36 @@ cursor: pointer; } -.monaco-button-dropdown > .monaco-dropdown-button { - margin-left: 1px; +.monaco-button-dropdown.disabled { + cursor: default; +} + +.monaco-button-dropdown > .monaco-button:focus { + outline-offset: -1px !important; +} + +.monaco-button-dropdown.disabled > .monaco-button.disabled, +.monaco-button-dropdown.disabled > .monaco-button.disabled:focus, +.monaco-button-dropdown.disabled > .monaco-button-dropdown-separator { + opacity: 0.4 !important; +} + +.monaco-button-dropdown > .monaco-button.monaco-text-button { + border-right-width: 0 !important; +} + +.monaco-button-dropdown .monaco-button-dropdown-separator { + padding: 4px 0; + cursor: default; +} + +.monaco-button-dropdown .monaco-button-dropdown-separator > div { + height: 100%; + width: 1px; +} + +.monaco-button-dropdown > .monaco-button.monaco-dropdown-button { + border-left-width: 0 !important; } .monaco-description-button { diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index a2349f9dc96..b7aea2c66f1 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -15,6 +15,7 @@ import { Emitter, Event as BaseEvent } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { mixin } from 'vs/base/common/objects'; +import { localize } from 'vs/nls'; import 'vs/css!./button'; export interface IButtonOptions extends IButtonStyles { @@ -27,6 +28,7 @@ export interface IButtonStyles { buttonBackground?: Color; buttonHoverBackground?: Color; buttonForeground?: Color; + buttonSeparator?: Color; buttonSecondaryBackground?: Color; buttonSecondaryHoverBackground?: Color; buttonSecondaryForeground?: Color; @@ -36,6 +38,7 @@ export interface IButtonStyles { const defaultOptions: IButtonStyles = { buttonBackground: Color.fromHex('#0E639C'), buttonHoverBackground: Color.fromHex('#006BB3'), + buttonSeparator: Color.white, buttonForeground: Color.white }; @@ -136,8 +139,8 @@ export class Button extends Disposable implements IButton { // Also set hover background when button is focused for feedback this.focusTracker = this._register(trackFocus(this._element)); - this._register(this.focusTracker.onDidFocus(() => this.setHoverBackground())); - this._register(this.focusTracker.onDidBlur(() => this.applyStyles())); // restore standard styles + this._register(this.focusTracker.onDidFocus(() => { if (this.enabled) { this.setHoverBackground(); } })); + this._register(this.focusTracker.onDidBlur(() => { if (this.enabled) { this.applyStyles(); } })); this.applyStyles(); } @@ -246,6 +249,8 @@ export class ButtonWithDropdown extends Disposable implements IButton { private readonly button: Button; private readonly action: Action; private readonly dropdownButton: Button; + private readonly separatorContainer: HTMLDivElement; + private readonly separator: HTMLDivElement; readonly element: HTMLElement; private readonly _onDidClick = this._register(new Emitter()); @@ -258,11 +263,21 @@ export class ButtonWithDropdown extends Disposable implements IButton { this.element.classList.add('monaco-button-dropdown'); container.appendChild(this.element); - this.button = this._register(new Button(this.element, options)); + this.button = this._register(new ButtonWithDescription(this.element, options)); this._register(this.button.onDidClick(e => this._onDidClick.fire(e))); this.action = this._register(new Action('primaryAction', this.button.label, undefined, true, async () => this._onDidClick.fire(undefined))); + this.separatorContainer = document.createElement('div'); + this.separatorContainer.classList.add('monaco-button-dropdown-separator'); + + this.separator = document.createElement('div'); + this.separatorContainer.appendChild(this.separator); + this.element.appendChild(this.separatorContainer); + this.dropdownButton = this._register(new Button(this.element, { ...options, title: false, supportIcons: true })); + this.dropdownButton.element.title = localize("button dropdown more actions", 'More Actions...'); + this.dropdownButton.element.setAttribute('aria-haspopup', 'true'); + this.dropdownButton.element.setAttribute('aria-expanded', 'false'); this.dropdownButton.element.classList.add('monaco-dropdown-button'); this.dropdownButton.icon = Codicon.dropDownButton; this._register(this.dropdownButton.onDidClick(e => { @@ -285,9 +300,15 @@ export class ButtonWithDropdown extends Disposable implements IButton { this.button.icon = icon; } + set description(value: string) { + (this.button as ButtonWithDescription).description = value; + } + set enabled(enabled: boolean) { this.button.enabled = enabled; this.dropdownButton.enabled = enabled; + + this.element.classList.toggle('disabled', !enabled); } get enabled(): boolean { @@ -297,6 +318,20 @@ export class ButtonWithDropdown extends Disposable implements IButton { style(styles: IButtonStyles): void { this.button.style(styles); this.dropdownButton.style(styles); + + // Separator + const border = styles.buttonBorder ? styles.buttonBorder.toString() : ''; + + this.separatorContainer.style.borderTopWidth = border ? '1px' : ''; + this.separatorContainer.style.borderTopStyle = border ? 'solid' : ''; + this.separatorContainer.style.borderTopColor = border; + + this.separatorContainer.style.borderBottomWidth = border ? '1px' : ''; + this.separatorContainer.style.borderBottomStyle = border ? 'solid' : ''; + this.separatorContainer.style.borderBottomColor = border; + + this.separatorContainer.style.backgroundColor = styles.buttonBackground?.toString() ?? ''; + this.separator.style.backgroundColor = styles.buttonSeparator?.toString() ?? ''; } focus(): void { @@ -320,12 +355,10 @@ export class ButtonWithDescription extends Button implements IButtonWithDescript this._labelElement = document.createElement('div'); this._labelElement.classList.add('monaco-button-label'); - this._labelElement.tabIndex = -1; this._element.appendChild(this._labelElement); this._descriptionElement = document.createElement('div'); this._descriptionElement.classList.add('monaco-button-description'); - this._descriptionElement.tabIndex = -1; this._element.appendChild(this._descriptionElement); } diff --git a/src/vs/base/browser/ui/centered/centeredViewLayout.ts b/src/vs/base/browser/ui/centered/centeredViewLayout.ts index b16ac4334ca..b746382e57a 100644 --- a/src/vs/base/browser/ui/centered/centeredViewLayout.ts +++ b/src/vs/base/browser/ui/centered/centeredViewLayout.ts @@ -159,9 +159,7 @@ export class CenteredViewLayout implements IDisposable { this.container.removeChild(this.splitView.el); } this.splitViewDisposables.clear(); - if (this.splitView) { - this.splitView.dispose(); - } + this.splitView?.dispose(); this.splitView = undefined; this.emptyViews = undefined; this.container.appendChild(this.view.element); diff --git a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf index 13999090718..d8ac87cba86 100644 Binary files a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf and b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf differ diff --git a/src/vs/base/browser/ui/contextview/contextview.css b/src/vs/base/browser/ui/contextview/contextview.css index bb7ebbcfdb2..cca41507ae9 100644 --- a/src/vs/base/browser/ui/contextview/contextview.css +++ b/src/vs/base/browser/ui/contextview/contextview.css @@ -5,7 +5,6 @@ .context-view { position: absolute; - z-index: 2500; } .context-view.fixed { @@ -13,6 +12,5 @@ font-family: inherit; font-size: 13px; position: fixed; - z-index: 2500; color: inherit; } diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index c75402d6aea..27958b235af 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -206,7 +206,7 @@ export class ContextView extends Disposable { this.view.className = 'context-view'; this.view.style.top = '0px'; this.view.style.left = '0px'; - this.view.style.zIndex = '2500'; + this.view.style.zIndex = '2575'; this.view.style.position = this.useFixedPosition ? 'fixed' : 'absolute'; DOM.show(this.view); diff --git a/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts index d389e0f0e78..b0f07682dd6 100644 --- a/src/vs/base/browser/ui/dropdown/dropdown.ts +++ b/src/vs/base/browser/ui/dropdown/dropdown.ts @@ -192,9 +192,7 @@ export class Dropdown extends BaseDropdown { override hide(): void { super.hide(); - if (this.contextViewProvider) { - this.contextViewProvider.hideContextView(); - } + this.contextViewProvider?.hideContextView(); } protected renderContents(container: HTMLElement): IDisposable | null { diff --git a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts index 0af76e3b6a0..75d35b2b4d7 100644 --- a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts +++ b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts @@ -3,8 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; import { IContextMenuProvider } from 'vs/base/browser/contextmenu'; -import { $, addDisposableListener, append, EventType } from 'vs/base/browser/dom'; +import { $, addDisposableListener, append, EventType, h } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { ActionViewItem, BaseActionViewItem, IActionViewItemOptions, IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; @@ -126,9 +127,22 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { }; } + this.updateTooltip(); this.updateEnabled(); } + override getTooltip(): string | undefined { + let title: string | null = null; + + if (this.action.tooltip) { + title = this.action.tooltip; + } else if (this.action.label) { + title = this.action.label; + } + + return title ?? undefined; + } + override setActionContext(newContext: unknown): void { super.setActionContext(newContext); @@ -142,13 +156,11 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { } show(): void { - if (this.dropdownMenu) { - this.dropdownMenu.show(); - } + this.dropdownMenu?.show(); } protected override updateEnabled(): void { - const disabled = !this.getAction().enabled; + const disabled = !this.action.enabled; this.actionItem?.classList.toggle('disabled', disabled); this.element?.classList.toggle('disabled', disabled); } @@ -182,7 +194,13 @@ export class ActionWithDropdownActionViewItem extends ActionViewItem { return Array.isArray(actionsProvider) ? actionsProvider : (actionsProvider as IActionProvider).getActions(); // TODO: microsoft/TypeScript#42768 } }; - this.dropdownMenuActionViewItem = new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', undefined)), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...Codicon.dropDownButton.classNamesArray, ...(this.options).menuActionClassNames || []] }); + + const menuActionClassNames = (this.options).menuActionClassNames || []; + const separator = h('div.action-dropdown-item-separator', [h('div', {})]).root; + separator.classList.toggle('prominent', menuActionClassNames.includes('prominent')); + append(this.element, separator); + + this.dropdownMenuActionViewItem = new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', nls.localize('moreActions', "More Actions..."))), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...Codicon.dropDownButton.classNamesArray, ...menuActionClassNames] }); this.dropdownMenuActionViewItem.render(this.element); this._register(addDisposableListener(this.element, EventType.KEY_DOWN, e => { diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts index b9e218ce03b..c164b2fe2a9 100644 --- a/src/vs/base/browser/ui/findinput/findInput.ts +++ b/src/vs/base/browser/ui/findinput/findInput.ts @@ -6,7 +6,7 @@ import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; -import { IToggleStyles } from 'vs/base/browser/ui/toggle/toggle'; +import { IToggleStyles, Toggle } from 'vs/base/browser/ui/toggle/toggle'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { CaseSensitiveToggle, RegexToggle, WholeWordsToggle } from 'vs/base/browser/ui/findinput/findInputToggles'; import { HistoryInputBox, IInputBoxStyles, IInputValidator, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -16,6 +16,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import 'vs/css!./findInput'; import * as nls from 'vs/nls'; +import { DisposableStore } from 'vs/base/common/lifecycle'; export interface IFindInputOptions extends IFindInputStyles { @@ -27,10 +28,12 @@ export interface IFindInputOptions extends IFindInputStyles { readonly flexibleWidth?: boolean; readonly flexibleMaxHeight?: number; + readonly showCommonFindToggles?: boolean; readonly appendCaseSensitiveLabel?: string; readonly appendWholeWordsLabel?: string; readonly appendRegexLabel?: string; readonly history?: string[]; + readonly additionalToggles?: Toggle[]; readonly showHistoryHint?: () => boolean; } @@ -46,12 +49,13 @@ export class FindInput extends Widget { static readonly OPTION_CHANGE: string = 'optionChange'; - private contextViewProvider: IContextViewProvider; private placeholder: string; private validation?: IInputValidator; private label: string; + private showCommonFindToggles: boolean; private fixFocusOnOptionClickEnabled = true; private imeSessionInProgress = false; + private additionalTogglesDisposables: DisposableStore = new DisposableStore(); protected inputActiveOptionBorder?: Color; protected inputActiveOptionForeground?: Color; @@ -74,6 +78,7 @@ export class FindInput extends Widget { protected regex: RegexToggle; protected wholeWords: WholeWordsToggle; protected caseSensitive: CaseSensitiveToggle; + protected additionalToggles: Toggle[] = []; public domNode: HTMLElement; public inputBox: HistoryInputBox; @@ -98,12 +103,12 @@ export class FindInput extends Widget { private _onRegexKeyDown = this._register(new Emitter()); public readonly onRegexKeyDown: Event = this._onRegexKeyDown.event; - constructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider, private readonly _showOptionButtons: boolean, options: IFindInputOptions) { + constructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, options: IFindInputOptions) { super(); - this.contextViewProvider = contextViewProvider; this.placeholder = options.placeholder || ''; this.validation = options.validation; this.label = options.label || NLS_DEFAULT_LABEL; + this.showCommonFindToggles = !!options.showCommonFindToggles; this.inputActiveOptionBorder = options.inputActiveOptionBorder; this.inputActiveOptionForeground = options.inputActiveOptionForeground; @@ -133,7 +138,7 @@ export class FindInput extends Widget { this.domNode = document.createElement('div'); this.domNode.classList.add('monaco-findInput'); - this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, { + this.inputBox = this._register(new HistoryInputBox(this.domNode, contextViewProvider, { placeholder: this.placeholder || '', ariaLabel: this.label || '', validationOptions: { @@ -209,10 +214,6 @@ export class FindInput extends Widget { this._onCaseSensitiveKeyDown.fire(e); })); - if (this._showOptionButtons) { - this.inputBox.paddingRight = this.caseSensitive.width() + this.wholeWords.width() + this.regex.width(); - } - // Arrow-Key support to navigate between options const indexes = [this.caseSensitive.domNode, this.wholeWords.domNode, this.regex.domNode]; this.onkeydown(this.domNode, (event: IKeyboardEvent) => { @@ -245,11 +246,19 @@ export class FindInput extends Widget { this.controls = document.createElement('div'); this.controls.className = 'controls'; - this.controls.style.display = this._showOptionButtons ? 'block' : 'none'; + this.controls.style.display = this.showCommonFindToggles ? 'block' : 'none'; this.controls.appendChild(this.caseSensitive.domNode); this.controls.appendChild(this.wholeWords.domNode); this.controls.appendChild(this.regex.domNode); + if (!this.showCommonFindToggles) { + this.caseSensitive.domNode.style.display = 'none'; + this.wholeWords.domNode.style.display = 'none'; + this.regex.domNode.style.display = 'none'; + } + + this.setAdditionalToggles(options?.additionalToggles); + this.domNode.appendChild(this.controls); parent?.appendChild(this.domNode); @@ -282,6 +291,10 @@ export class FindInput extends Widget { this.regex.enable(); this.wholeWords.enable(); this.caseSensitive.enable(); + + for (const toggle of this.additionalToggles) { + toggle.enable(); + } } public disable(): void { @@ -290,6 +303,10 @@ export class FindInput extends Widget { this.regex.disable(); this.wholeWords.disable(); this.caseSensitive.disable(); + + for (const toggle of this.additionalToggles) { + toggle.disable(); + } } public setFocusInputOnOptionClick(value: boolean): void { @@ -304,6 +321,37 @@ export class FindInput extends Widget { } } + public setAdditionalToggles(toggles: Toggle[] | undefined): void { + for (const currentToggle of this.additionalToggles) { + currentToggle.domNode.remove(); + } + this.additionalToggles = []; + this.additionalTogglesDisposables.dispose(); + this.additionalTogglesDisposables = new DisposableStore(); + + for (const toggle of toggles ?? []) { + this.additionalTogglesDisposables.add(toggle); + this.controls.appendChild(toggle.domNode); + + this.additionalTogglesDisposables.add(toggle.onChange(viaKeyboard => { + this._onDidOptionChange.fire(viaKeyboard); + if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) { + this.inputBox.focus(); + } + })); + + this.additionalToggles.push(toggle); + } + + if (this.additionalToggles.length > 0) { + this.controls.style.display = 'block'; + } + + this.inputBox.paddingRight = + (this.showCommonFindToggles ? this.caseSensitive.width() + this.wholeWords.width() + this.regex.width() : 0) + + this.additionalToggles.reduce((r, t) => r + t.width(), 0); + } + public clear(): void { this.clearValidation(); this.setValue(''); @@ -356,6 +404,10 @@ export class FindInput extends Widget { this.wholeWords.style(toggleStyles); this.caseSensitive.style(toggleStyles); + for (const toggle of this.additionalToggles) { + toggle.style(toggleStyles); + } + const inputBoxStyles: IInputBoxStyles = { inputBackground: this.inputBackground, inputForeground: this.inputForeground, diff --git a/src/vs/base/browser/ui/findinput/replaceInput.ts b/src/vs/base/browser/ui/findinput/replaceInput.ts index a80c5a1faaf..2861edde0b8 100644 --- a/src/vs/base/browser/ui/findinput/replaceInput.ts +++ b/src/vs/base/browser/ui/findinput/replaceInput.ts @@ -353,9 +353,7 @@ export class ReplaceInput extends Widget { } public validate(): void { - if (this.inputBox) { - this.inputBox.validate(); - } + this.inputBox?.validate(); } public showMessage(message: InputBoxMessage): void { @@ -363,15 +361,11 @@ export class ReplaceInput extends Widget { } public clearMessage(): void { - if (this.inputBox) { - this.inputBox.hideMessage(); - } + this.inputBox?.hideMessage(); } private clearValidation(): void { - if (this.inputBox) { - this.inputBox.hideMessage(); - } + this.inputBox?.hideMessage(); } public set width(newWidth: number) { diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index e4cbed18667..cf8798982b0 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -527,6 +527,16 @@ export class Grid extends Disposable { return this.gridview.resizeView(location, size); } + /** + * Returns whether all other {@link IView views} are at their minimum size. + * + * @param view The reference {@link IView view}. + */ + isViewSizeMaximized(view: T): boolean { + const location = this.getViewLocation(view); + return this.gridview.isViewSizeMaximized(location); + } + /** * Get the size of a {@link IView view}. * diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index e121bcc10c8..8457663d657 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -592,6 +592,10 @@ class BranchNode implements ISplitView, IDisposable { this.splitview.resizeView(index, size); } + isChildSizeMaximized(index: number): boolean { + return this.splitview.isViewSizeMaximized(index); + } + distributeViewSizes(recursive = false): void { this.splitview.distributeViewSizes(); @@ -1431,6 +1435,27 @@ export class GridView implements IDisposable { } } + /** + * Returns whether all other {@link IView views} are at their minimum size. + * + * @param location The {@link GridLocation location} of the view. + */ + isViewSizeMaximized(location: GridLocation): boolean { + const [ancestors, node] = this.getNode(location); + + if (!(node instanceof LeafNode)) { + throw new Error('Invalid location'); + } + + for (let i = 0; i < ancestors.length; i++) { + if (!ancestors[i].isChildSizeMaximized(location[i])) { + return false; + } + } + + return true; + } + /** * Distribute the size among all {@link IView views} within the entire * grid or within a single {@link SplitView}. diff --git a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts index 3b69763252e..18c2d093f00 100644 --- a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts +++ b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts @@ -96,10 +96,10 @@ export class HighlightedLabel { if (pos < highlight.start) { const substring = this.text.substring(pos, highlight.start); children.push(dom.$('span', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring])); - pos = highlight.end; + pos = highlight.start; } - const substring = this.text.substring(highlight.start, highlight.end); + const substring = this.text.substring(pos, highlight.end); const element = dom.$('span.highlight', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]); if (highlight.extraClasses) { diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 5e7ff8fa7de..dbd32cc5e67 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -30,6 +30,7 @@ export interface IIconLabelValueOptions { matches?: IMatch[]; labelEscapeNewLines?: boolean; descriptionMatches?: IMatch[]; + disabledCommand?: boolean; readonly separator?: string; readonly domId?: string; } @@ -124,22 +125,28 @@ export class IconLabel extends Disposable { } setLabel(label: string | string[], description?: string, options?: IIconLabelValueOptions): void { - const classes = ['monaco-icon-label']; + const labelClasses = ['monaco-icon-label']; + const containerClasses = ['monaco-icon-label-container']; if (options) { if (options.extraClasses) { - classes.push(...options.extraClasses); + labelClasses.push(...options.extraClasses); } if (options.italic) { - classes.push('italic'); + labelClasses.push('italic'); } if (options.strikethrough) { - classes.push('strikethrough'); + labelClasses.push('strikethrough'); + } + + if (options.disabledCommand) { + containerClasses.push('disabled'); } } - this.domNode.className = classes.join(' '); + this.domNode.className = labelClasses.join(' '); + this.labelContainer.className = containerClasses.join(' '); this.setupHover(options?.descriptionTitle ? this.labelContainer : this.element, options?.title); this.nameNode.setLabel(label, options); diff --git a/src/vs/base/browser/ui/iconLabel/iconLabels.ts b/src/vs/base/browser/ui/iconLabel/iconLabels.ts index 103bca257a5..4fe1a5c79e8 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabels.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabels.ts @@ -9,7 +9,7 @@ import { CSSIcon } from 'vs/base/common/codicons'; const labelWithIconsRegex = new RegExp(`(\\\\)?\\$\\((${CSSIcon.iconNameExpression}(?:${CSSIcon.iconModifierExpression})?)\\)`, 'g'); export function renderLabelWithIcons(text: string): Array { const elements = new Array(); - let match: RegExpMatchArray | null; + let match: RegExpExecArray | null; let textStart = 0, textStop = 0; while ((match = labelWithIconsRegex.exec(text)) !== null) { diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index 45b73bece04..ab4c0e131eb 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -31,6 +31,9 @@ flex-shrink: 0; /* fix for https://github.com/microsoft/vscode/issues/13787 */ } +.monaco-icon-label-container.disabled { + color: var(--vscode-disabledForeground); +} .monaco-icon-label > .monaco-icon-label-container { min-width: 0; overflow: hidden; diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index a3087e1c9c1..ae89cb33f38 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -621,9 +621,7 @@ export class InputBox extends Widget { this.message = null; - if (this.actionbar) { - this.actionbar.dispose(); - } + this.actionbar?.dispose(); super.dispose(); } diff --git a/src/vs/base/browser/ui/list/list.css b/src/vs/base/browser/ui/list/list.css index eaca3ae8bd8..84cda4cfae3 100644 --- a/src/vs/base/browser/ui/list/list.css +++ b/src/vs/base/browser/ui/list/list.css @@ -65,72 +65,7 @@ z-index: 1000; } -/* Type filter */ - -.monaco-list-type-filter { - display: flex; - align-items: center; - position: absolute; - border-radius: 2px; - padding: 0px 3px; - max-width: calc(100% - 10px); - text-overflow: ellipsis; - overflow: hidden; - text-align: right; - box-sizing: border-box; - cursor: all-scroll; - font-size: 13px; - line-height: 18px; - height: 20px; - z-index: 1; - top: 4px; -} - -.monaco-list-type-filter.dragging { - transition: top 0.2s, left 0.2s; -} - -.monaco-list-type-filter.ne { - right: 4px; -} - -.monaco-list-type-filter.nw { - left: 4px; -} - -.monaco-list-type-filter > .controls { - display: flex; - align-items: center; - box-sizing: border-box; - transition: width 0.2s; - width: 0; -} - -.monaco-list-type-filter.dragging > .controls, -.monaco-list-type-filter:hover > .controls { - width: 36px; -} - -.monaco-list-type-filter > .controls > * { - border: none; - box-sizing: border-box; - -webkit-appearance: none; - -moz-appearance: none; - background: none; - width: 16px; - height: 16px; - flex-shrink: 0; - margin: 0; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; -} - -.monaco-list-type-filter > .controls > .filter { - margin-left: 4px; -} +/* Filter */ .monaco-list-type-filter-message { position: absolute; @@ -149,13 +84,3 @@ .monaco-list-type-filter-message:empty { display: none; } - -/* Electron */ - -.monaco-list-type-filter { - cursor: grab; -} - -.monaco-list-type-filter.dragging { - cursor: grabbing; -} diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 43d4ad49e81..a5f3a920e38 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -12,7 +12,7 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { IThemable } from 'vs/base/common/styler'; import 'vs/css!./list'; import { IListContextMenuEvent, IListEvent, IListMouseEvent, IListRenderer, IListVirtualDelegate } from './list'; -import { IListAccessibilityProvider, IListOptions, IListOptionsUpdate, IListStyles, List } from './listWidget'; +import { IListAccessibilityProvider, IListOptions, IListOptionsUpdate, IListStyles, List, TypeNavigationMode } from './listWidget'; export interface IPagedRenderer extends IListRenderer { renderPlaceholder(index: number, templateData: TTemplateData): void; @@ -38,9 +38,7 @@ class PagedRenderer implements IListRenderer, height: number | undefined): void { - if (data.disposable) { - data.disposable.dispose(); - } + data.disposable?.dispose(); if (!data.data) { return; @@ -95,8 +93,8 @@ class PagedAccessibilityProvider implements IListAccessibilityProvider { - readonly enableKeyboardNavigation?: boolean; - readonly automaticKeyboardNavigation?: boolean; + readonly typeNavigationEnabled?: boolean; + readonly typeNavigationMode?: TypeNavigationMode; readonly ariaLabel?: string; readonly keyboardSupport?: boolean; readonly multipleSelectionSupport?: boolean; @@ -282,8 +280,8 @@ export class PagedList implements IThemable, IDisposable { this.list.layout(height, width); } - toggleKeyboardNavigation(): void { - this.list.toggleKeyboardNavigation(); + triggerTypeNavigation(): void { + this.list.triggerTypeNavigation(); } reveal(index: number, relativeTop?: number): void { diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index a396809facb..7e9f2aecba6 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { isFirefox } from 'vs/base/browser/browser'; -import { DataTransfers, IDragAndDropData, StaticDND } from 'vs/base/browser/dnd'; +import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd'; import { $, addDisposableListener, animate, getContentHeight, getContentWidth, getTopLeftOffset, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; @@ -38,6 +38,10 @@ interface IItem { checkedDisposable: IDisposable; } +const StaticDND = { + CurrentDragAndDropData: undefined as IDragAndDropData | undefined +}; + export interface IListViewDragAndDrop extends IListDragAndDrop { getDragElements(element: T): T[]; } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 20df7f37ba8..8ed5f2d8602 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -4,11 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { IDragAndDropData } from 'vs/base/browser/dnd'; -import { createStyleSheet } from 'vs/base/browser/dom'; -import { DomEmitter, stopEvent } from 'vs/base/browser/event'; +import { createStyleSheet, EventHelper } from 'vs/base/browser/dom'; +import { DomEmitter } from 'vs/base/browser/event'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Gesture } from 'vs/base/browser/touch'; import { alert } from 'vs/base/browser/ui/aria/aria'; +import { IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput'; import { CombinedSpliceable } from 'vs/base/browser/ui/list/splice'; import { ScrollableElementChangeOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions'; import { binarySearch, firstOrDefault, range } from 'vs/base/common/arrays'; @@ -258,6 +259,23 @@ export function isMonacoEditor(e: HTMLElement): boolean { return isMonacoEditor(e.parentElement); } +export function isButton(e: HTMLElement): boolean { + if ((e.tagName === 'A' && e.classList.contains('monaco-button')) || + (e.tagName === 'DIV' && e.classList.contains('monaco-button-dropdown'))) { + return true; + } + + if (e.classList.contains('monaco-list')) { + return false; + } + + if (!e.parentElement) { + return false; + } + + return isButton(e.parentElement); +} + class KeyboardController implements IDisposable { private readonly disposables = new DisposableStore(); @@ -367,7 +385,12 @@ class KeyboardController implements IDisposable { } } -enum TypeLabelControllerState { +export enum TypeNavigationMode { + Automatic, + Trigger +} + +enum TypeNavigationControllerState { Idle, Typing } @@ -385,12 +408,12 @@ export const DefaultKeyboardNavigationDelegate = new class implements IKeyboardN } }; -class TypeLabelController implements IDisposable { +class TypeNavigationController implements IDisposable { private enabled = false; - private state: TypeLabelControllerState = TypeLabelControllerState.Idle; + private state: TypeNavigationControllerState = TypeNavigationControllerState.Idle; - private automaticKeyboardNavigation = true; + private mode = TypeNavigationMode.Automatic; private triggered = false; private previouslyFocused = -1; @@ -401,26 +424,23 @@ class TypeLabelController implements IDisposable { private list: List, private view: ListView, private keyboardNavigationLabelProvider: IKeyboardNavigationLabelProvider, + private keyboardNavigationEventFilter: IKeyboardNavigationEventFilter, private delegate: IKeyboardNavigationDelegate ) { this.updateOptions(list.options); } updateOptions(options: IListOptions): void { - const enableKeyboardNavigation = typeof options.enableKeyboardNavigation === 'undefined' ? true : !!options.enableKeyboardNavigation; - - if (enableKeyboardNavigation) { + if (options.typeNavigationEnabled ?? true) { this.enable(); } else { this.disable(); } - if (typeof options.automaticKeyboardNavigation !== 'undefined') { - this.automaticKeyboardNavigation = options.automaticKeyboardNavigation; - } + this.mode = options.typeNavigationMode ?? TypeNavigationMode.Automatic; } - toggle(): void { + trigger(): void { this.triggered = !this.triggered; } @@ -429,12 +449,15 @@ class TypeLabelController implements IDisposable { return; } + let typing = false; + const onChar = this.enabledDisposables.add(Event.chain(this.enabledDisposables.add(new DomEmitter(this.view.domNode, 'keydown')).event)) .filter(e => !isInputElement(e.target as HTMLElement)) - .filter(() => this.automaticKeyboardNavigation || this.triggered) + .filter(() => this.mode === TypeNavigationMode.Automatic || this.triggered) .map(event => new StandardKeyboardEvent(event)) + .filter(e => typing || this.keyboardNavigationEventFilter(e)) .filter(e => this.delegate.mightProducePrintableCharacter(e)) - .forEach(e => e.preventDefault()) + .forEach(e => EventHelper.stop(e, true)) .map(event => event.browserEvent.key) .event; @@ -444,6 +467,9 @@ class TypeLabelController implements IDisposable { onInput(this.onInput, this, this.enabledDisposables); onClear(this.onClear, this, this.enabledDisposables); + onChar(() => typing = true, undefined, this.enabledDisposables); + onClear(() => typing = false, undefined, this.enabledDisposables); + this.enabled = true; this.triggered = false; } @@ -473,15 +499,15 @@ class TypeLabelController implements IDisposable { private onInput(word: string | null): void { if (!word) { - this.state = TypeLabelControllerState.Idle; + this.state = TypeNavigationControllerState.Idle; this.triggered = false; return; } const focus = this.list.getFocus(); const start = focus.length > 0 ? focus[0] : 0; - const delta = this.state === TypeLabelControllerState.Idle ? 1 : 0; - this.state = TypeLabelControllerState.Typing; + const delta = this.state === TypeNavigationControllerState.Idle ? 1 : 0; + this.state = TypeNavigationControllerState.Typing; for (let i = 0; i < this.list.length; i++) { const index = (start + i + delta) % this.list.length; @@ -878,22 +904,6 @@ export class DefaultStyleController implements IStyleController { `); } - if (styles.listFilterWidgetBackground) { - content.push(`.monaco-list-type-filter { background-color: ${styles.listFilterWidgetBackground} }`); - } - - if (styles.listFilterWidgetOutline) { - content.push(`.monaco-list-type-filter { border: 1px solid ${styles.listFilterWidgetOutline}; }`); - } - - if (styles.listFilterWidgetNoMatchesOutline) { - content.push(`.monaco-list-type-filter.no-matches { border: 1px solid ${styles.listFilterWidgetNoMatchesOutline}; }`); - } - - if (styles.listMatchesShadow) { - content.push(`.monaco-list-type-filter { box-shadow: 1px 1px 1px ${styles.listMatchesShadow}; }`); - } - if (styles.tableColumnsBorder) { content.push(` .monaco-table:hover > .monaco-split-view2, @@ -916,9 +926,13 @@ export class DefaultStyleController implements IStyleController { } } +export interface IKeyboardNavigationEventFilter { + (e: StandardKeyboardEvent): boolean; +} + export interface IListOptionsUpdate extends IListViewOptionsUpdate { - readonly enableKeyboardNavigation?: boolean; - readonly automaticKeyboardNavigation?: boolean; + readonly typeNavigationEnabled?: boolean; + readonly typeNavigationMode?: TypeNavigationMode; readonly multipleSelectionSupport?: boolean; } @@ -931,6 +945,7 @@ export interface IListOptions extends IListOptionsUpdate { readonly multipleSelectionController?: IMultipleSelectionController; readonly styleController?: (suffix: string) => IStyleController; readonly accessibilityProvider?: IListAccessibilityProvider; + readonly keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter; // list view options readonly useShadows?: boolean; @@ -947,7 +962,7 @@ export interface IListOptions extends IListOptionsUpdate { readonly alwaysConsumeMouseWheel?: boolean; } -export interface IListStyles { +export interface IListStyles extends IFindInputStyles { listBackground?: Color; listFocusBackground?: Color; listFocusForeground?: Color; @@ -972,7 +987,7 @@ export interface IListStyles { listFilterWidgetBackground?: Color; listFilterWidgetOutline?: Color; listFilterWidgetNoMatchesOutline?: Color; - listMatchesShadow?: Color; + listFilterWidgetShadow?: Color; treeIndentGuidesStroke?: Color; tableColumnsBorder?: Color; tableOddRowsBackgroundColor?: Color; @@ -1230,7 +1245,7 @@ export class List implements ISpliceable, IThemable, IDisposable { protected view: ListView; private spliceable: ISpliceable; private styleController: IStyleController; - private typeLabelController?: TypeLabelController; + private typeNavigationController?: TypeNavigationController; private accessibilityProvider?: IListAccessibilityProvider; private keyboardController: KeyboardController | undefined; private mouseController: MouseController; @@ -1273,7 +1288,7 @@ export class List implements ISpliceable, IThemable, IDisposable { const fromKeyDown = this.disposables.add(Event.chain(this.disposables.add(new DomEmitter(this.view.domNode, 'keydown')).event)) .map(e => new StandardKeyboardEvent(e)) .filter(e => didJustPressContextMenuKey = e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10)) - .map(stopEvent) + .map(e => EventHelper.stop(e, true)) .filter(() => false) .event as Event; @@ -1281,7 +1296,7 @@ export class List implements ISpliceable, IThemable, IDisposable { .forEach(() => didJustPressContextMenuKey = false) .map(e => new StandardKeyboardEvent(e)) .filter(e => e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10)) - .map(stopEvent) + .map(e => EventHelper.stop(e, true)) .map(({ browserEvent }) => { const focus = this.getFocus(); const index = focus.length ? focus[0] : undefined; @@ -1370,8 +1385,8 @@ export class List implements ISpliceable, IThemable, IDisposable { if (_options.keyboardNavigationLabelProvider) { const delegate = _options.keyboardNavigationDelegate || DefaultKeyboardNavigationDelegate; - this.typeLabelController = new TypeLabelController(this, this.view, _options.keyboardNavigationLabelProvider, delegate); - this.disposables.add(this.typeLabelController); + this.typeNavigationController = new TypeNavigationController(this, this.view, _options.keyboardNavigationLabelProvider, _options.keyboardNavigationEventFilter ?? (() => true), delegate); + this.disposables.add(this.typeNavigationController); } this.mouseController = this.createMouseController(_options); @@ -1396,7 +1411,7 @@ export class List implements ISpliceable, IThemable, IDisposable { updateOptions(optionsUpdate: IListOptionsUpdate = {}): void { this._options = { ...this._options, ...optionsUpdate }; - this.typeLabelController?.updateOptions(this._options); + this.typeNavigationController?.updateOptions(this._options); if (this._options.multipleSelectionController !== undefined) { if (this._options.multipleSelectionSupport) { @@ -1512,10 +1527,8 @@ export class List implements ISpliceable, IThemable, IDisposable { this.view.layout(height, width); } - toggleKeyboardNavigation(): void { - if (this.typeLabelController) { - this.typeLabelController.toggle(); - } + triggerTypeNavigation(): void { + this.typeNavigationController?.trigger(); } setSelection(indexes: number[], browserEvent?: UIEvent): void { @@ -1782,6 +1795,10 @@ export class List implements ISpliceable, IThemable, IDisposable { return this.view.domNode; } + getElementID(index: number): string { + return this.view.getElementDomId(index); + } + style(styles: IListStyles): void { this.styleController.style(styles); } diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index dce1f797feb..e4f1e20ffd9 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -33,8 +33,7 @@ export const MENU_ESCAPED_MNEMONIC_REGEX = /(&)?(&)([^\s&])/g; export enum Direction { Right, - Left, - Down + Left } export interface IMenuOptions { @@ -447,7 +446,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { // Set mnemonic if (this.options.label && options.enableMnemonics) { - const label = this.getAction().label; + const label = this.action.label; if (label) { const matches = MENU_MNEMONIC_REGEX.exec(label); if (matches) { @@ -553,9 +552,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { override focus(): void { super.focus(); - if (this.item) { - this.item.focus(); - } + this.item?.focus(); this.applyStyle(); } @@ -575,7 +572,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { if (this.options.label) { clearNode(this.label); - let label = stripIcons(this.getAction().label); + let label = stripIcons(this.action.label); if (label) { const cleanLabel = cleanMnemonic(label); if (!this.options.enableMnemonics) { @@ -627,7 +624,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { this.item.classList.remove(...this.cssClass.split(' ')); } if (this.options.icon && this.label) { - this.cssClass = this.getAction().class || ''; + this.cssClass = this.action.class || ''; this.label.classList.add('icon'); if (this.cssClass) { this.label.classList.add(...this.cssClass.split(' ')); @@ -639,7 +636,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { } override updateEnabled(): void { - if (this.getAction().enabled) { + if (this.action.enabled) { if (this.element) { this.element.classList.remove('disabled'); this.element.removeAttribute('aria-disabled'); @@ -668,7 +665,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { return; } - const checked = this.getAction().checked; + const checked = this.action.checked; this.item.classList.toggle('checked', !!checked); if (checked !== undefined) { this.item.setAttribute('role', 'menuitemcheckbox'); diff --git a/src/vs/base/browser/ui/menu/menubar.css b/src/vs/base/browser/ui/menu/menubar.css index 64e309bf5dc..3a65f9a8829 100644 --- a/src/vs/base/browser/ui/menu/menubar.css +++ b/src/vs/base/browser/ui/menu/menubar.css @@ -13,6 +13,10 @@ overflow: hidden; } +.menubar.overflow-menu-only { + width: 38px; +} + .fullscreen .menubar:not(.compact) { margin: 0px; padding: 4px 5px; @@ -93,6 +97,7 @@ justify-content: center; } +.menubar:not(.compact) .menubar-menu-button:first-child .toolbar-toggle-more::before, .menubar.compact .toolbar-toggle-more::before { content: "\eb94" !important; } diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index 10dd697e7a4..fa843ff260a 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -334,8 +334,6 @@ export class MenuBar extends Disposable { triggerKeys.push(KeyCode.RightArrow); } else if (this.options.compactMode === Direction.Left) { triggerKeys.push(KeyCode.LeftArrow); - } else if (this.options.compactMode === Direction.Down) { - triggerKeys.push(KeyCode.DownArrow); } } @@ -475,6 +473,11 @@ export class MenuBar extends Disposable { return; } + const overflowMenuOnlyClass = 'overflow-menu-only'; + + // Remove overflow only restriction to allow the most space + this.container.classList.toggle(overflowMenuOnlyClass, false); + const sizeAvailable = this.container.offsetWidth; let currentSize = 0; let full = this.isCompact; @@ -501,6 +504,18 @@ export class MenuBar extends Disposable { } } + + // If below minimium menu threshold, show the overflow menu only as hamburger menu + if (this.numMenusShown - 1 <= showableMenus.length / 2) { + for (const menuBarMenu of showableMenus) { + menuBarMenu.buttonElement.style.visibility = 'hidden'; + } + + full = true; + this.numMenusShown = 0; + currentSize = 0; + } + // Overflow if (this.isCompact) { this.overflowMenu.actions = []; @@ -540,6 +555,9 @@ export class MenuBar extends Disposable { this.container.appendChild(this.overflowMenu.buttonElement); this.overflowMenu.buttonElement.style.visibility = 'hidden'; } + + // If we are only showing the overflow, add this class to avoid taking up space + this.container.classList.toggle(overflowMenuOnlyClass, this.numMenusShown === 0); } private updateLabels(titleElement: HTMLElement, buttonElement: HTMLElement, label: string): void { @@ -967,9 +985,7 @@ export class MenuBar extends Disposable { this.focusedMenu.holder.remove(); } - if (this.focusedMenu.widget) { - this.focusedMenu.widget.dispose(); - } + this.focusedMenu.widget?.dispose(); this.focusedMenu = { index: this.focusedMenu.index }; } diff --git a/src/vs/editor/contrib/suggest/browser/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts similarity index 100% rename from src/vs/editor/contrib/suggest/browser/resizable.ts rename to src/vs/base/browser/ui/resizable/resizable.ts diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 80ab505126e..4bc8ff1b8ee 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $, append, createStyleSheet, EventHelper, EventLike, getElementsByTagName } from 'vs/base/browser/dom'; +import { $, append, createStyleSheet, EventHelper, EventLike } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch'; import { Delayer } from 'vs/base/common/async'; @@ -493,7 +493,7 @@ export class Sash extends Disposable { return; } - const iframes = getElementsByTagName('iframe'); + const iframes = document.getElementsByTagName('iframe'); for (const iframe of iframes) { iframe.classList.add(PointerEventsDisabledCssClass); // disable mouse events on iframes as long as we drag the sash } diff --git a/src/vs/base/browser/ui/selectBox/selectBox.css b/src/vs/base/browser/ui/selectBox/selectBox.css index d296d1ff0a0..c0a54d83b27 100644 --- a/src/vs/base/browser/ui/selectBox/selectBox.css +++ b/src/vs/base/browser/ui/selectBox/selectBox.css @@ -5,6 +5,7 @@ .monaco-select-box { width: 100%; + cursor: pointer; } .monaco-select-box-dropdown-container { diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 57fbf0b1544..159c58a2797 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -52,7 +52,7 @@ export interface IView { readonly minimumSize: number; /** - * A minimum size for this view. + * A maximum size for this view. * * @remarks If none, set it to `Number.POSITIVE_INFINITY`. */ @@ -931,6 +931,23 @@ export class SplitView extends Disposable { this.state = State.Idle; } + /** + * Returns whether all other {@link IView views} are at their minimum size. + */ + isViewSizeMaximized(index: number): boolean { + if (index < 0 || index >= this.viewItems.length) { + return false; + } + + for (const item of this.viewItems) { + if (item !== this.viewItems[index] && item.size > item.minimumSize) { + return false; + } + } + + return true; + } + /** * Distribute the entire {@link SplitView} size among all {@link IView views}. */ diff --git a/src/vs/base/browser/ui/table/tableWidget.ts b/src/vs/base/browser/ui/table/tableWidget.ts index 03f6f284785..7f1d0560335 100644 --- a/src/vs/base/browser/ui/table/tableWidget.ts +++ b/src/vs/base/browser/ui/table/tableWidget.ts @@ -265,8 +265,8 @@ export class Table implements ISpliceable, IThemable, IDisposable { this.list.layout(listHeight, width); } - toggleKeyboardNavigation(): void { - this.list.toggleKeyboardNavigation(); + triggerTypeNavigation(): void { + this.list.triggerTypeNavigation(); } style(styles: ITableStyles): void { diff --git a/src/vs/base/browser/ui/toggle/toggle.ts b/src/vs/base/browser/ui/toggle/toggle.ts index 8d2387dbc26..8e7266a2d94 100644 --- a/src/vs/base/browser/ui/toggle/toggle.ts +++ b/src/vs/base/browser/ui/toggle/toggle.ts @@ -148,6 +148,7 @@ export class Toggle extends Widget { this.checked = !this._checked; this._onChange.fire(true); keyboardEvent.preventDefault(); + keyboardEvent.stopPropagation(); return; } diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index c03f5c5e1af..f592bca1564 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -3,27 +3,34 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DragAndDropData, IDragAndDropData, StaticDND } from 'vs/base/browser/dnd'; -import { $, addDisposableListener, append, clearNode, createStyleSheet, getDomNodePagePosition, hasParentWithClass } from 'vs/base/browser/dom'; +import { IDragAndDropData } from 'vs/base/browser/dnd'; +import { $, append, clearNode, createStyleSheet, h, hasParentWithClass } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { IIdentityProvider, IKeyboardNavigationDelegate, IKeyboardNavigationLabelProvider, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IListMouseEvent, IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; +import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput'; +import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; +import { IIdentityProvider, IKeyboardNavigationLabelProvider, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IListMouseEvent, IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; -import { DefaultKeyboardNavigationDelegate, IListOptions, IListStyles, isInputElement, isMonacoEditor, List, MouseController } from 'vs/base/browser/ui/list/listWidget'; +import { IListOptions, IListStyles, isButton, isInputElement, isMonacoEditor, List, MouseController, TypeNavigationMode } from 'vs/base/browser/ui/list/listWidget'; +import { Toggle } from 'vs/base/browser/ui/toggle/toggle'; import { getVisibleState, isFilterResult } from 'vs/base/browser/ui/tree/indexTreeModel'; import { ICollapseStateChangeEvent, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeEvent, ITreeFilter, ITreeModel, ITreeModelSpliceEvent, ITreeMouseEvent, ITreeNavigator, ITreeNode, ITreeRenderer, TreeDragOverBubble, TreeError, TreeFilterResult, TreeMouseEventTarget, TreeVisibility } from 'vs/base/browser/ui/tree/tree'; +import { Action } from 'vs/base/common/actions'; import { distinct, equals, firstOrDefault, range } from 'vs/base/common/arrays'; -import { disposableTimeout } from 'vs/base/common/async'; +import { disposableTimeout, timeout } from 'vs/base/common/async'; import { Codicon } from 'vs/base/common/codicons'; import { SetMap } from 'vs/base/common/collections'; +import { Color } from 'vs/base/common/color'; import { Emitter, Event, EventBufferer, Relay } from 'vs/base/common/event'; import { fuzzyScore, FuzzyScore } from 'vs/base/common/filters'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { clamp } from 'vs/base/common/numbers'; -import { isMacintosh } from 'vs/base/common/platform'; import { ScrollEvent } from 'vs/base/common/scrollable'; import { ISpliceable } from 'vs/base/common/sequence'; +import { isNumber } from 'vs/base/common/types'; import 'vs/css!./media/tree'; import { localize } from 'vs/nls'; @@ -194,8 +201,7 @@ function asListOptions(modelProvider: () => ITreeModel implements IListRenderer export type LabelFuzzyScore = { label: string; score: FuzzyScore }; -class TypeFilter implements ITreeFilter, IDisposable { +class FindFilter implements ITreeFilter, IDisposable { private _totalCount = 0; get totalCount(): number { return this._totalCount; } private _matchCount = 0; @@ -587,15 +593,11 @@ class TypeFilter implements ITreeFilter, IDi } filter(element: T, parentVisibility: TreeVisibility): TreeFilterResult { + let visibility = TreeVisibility.Visible; + if (this._filter) { const result = this._filter.filter(element, parentVisibility); - if (this.tree.options.simpleKeyboardNavigation) { - return result; - } - - let visibility: TreeVisibility; - if (typeof result === 'boolean') { visibility = result ? TreeVisibility.Visible : TreeVisibility.Hidden; } else if (isFilterResult(result)) { @@ -611,9 +613,9 @@ class TypeFilter implements ITreeFilter, IDi this._totalCount++; - if (this.tree.options.simpleKeyboardNavigation || !this._pattern) { + if (!this._pattern) { this._matchCount++; - return { data: FuzzyScore.Default, visibility: true }; + return { data: FuzzyScore.Default, visibility }; } const label = this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(element); @@ -622,22 +624,22 @@ class TypeFilter implements ITreeFilter, IDi for (const l of labels) { const labelStr = l && l.toString(); if (typeof labelStr === 'undefined') { - return { data: FuzzyScore.Default, visibility: true }; + return { data: FuzzyScore.Default, visibility }; } const score = fuzzyScore(this._pattern, this._lowercasePattern, 0, labelStr, labelStr.toLowerCase(), 0, { firstMatchCanBeWeak: true, boostFullMatch: true }); if (score) { this._matchCount++; return labels.length === 1 ? - { data: score, visibility: true } : - { data: { label: labelStr, score: score }, visibility: true }; + { data: score, visibility } : + { data: { label: labelStr, score: score }, visibility }; } } - if (this.tree.options.filterOnType) { + if (this.tree.findMode === TreeFindMode.Filter) { return TreeVisibility.Recurse; } else { - return { data: FuzzyScore.Default, visibility: true }; + return { data: FuzzyScore.Default, visibility }; } } @@ -651,170 +653,283 @@ class TypeFilter implements ITreeFilter, IDi } } -class TypeFilterController implements IDisposable { +export interface ICaseSensitiveToggleOpts { + readonly isChecked: boolean; + readonly inputActiveOptionBorder?: Color; + readonly inputActiveOptionForeground?: Color; + readonly inputActiveOptionBackground?: Color; +} - private _enabled = false; - get enabled(): boolean { return this._enabled; } +export class ModeToggle extends Toggle { + constructor(opts?: ICaseSensitiveToggleOpts) { + super({ + icon: Codicon.listFilter, + title: localize('filter', "Filter"), + isChecked: opts?.isChecked ?? false, + inputActiveOptionBorder: opts?.inputActiveOptionBorder, + inputActiveOptionForeground: opts?.inputActiveOptionForeground, + inputActiveOptionBackground: opts?.inputActiveOptionBackground + }); + } +} + +export interface IFindWidgetStyles extends IFindInputStyles, IListStyles { } + +export interface IFindWidgetOpts extends IFindWidgetStyles { } + +export enum TreeFindMode { + Highlight, + Filter +} + +class FindWidget extends Disposable { + + private readonly elements = h('.monaco-tree-type-filter', [ + h('.monaco-tree-type-filter-grab.codicon.codicon-debug-gripper@grab', { tabIndex: 0 }), + h('.monaco-tree-type-filter-input@findInput'), + h('.monaco-tree-type-filter-actionbar@actionbar'), + ]); + + set mode(mode: TreeFindMode) { + this.modeToggle.checked = mode === TreeFindMode.Filter; + this.findInput.inputBox.setPlaceHolder(mode === TreeFindMode.Filter ? localize('type to filter', "Type to filter") : localize('type to search', "Type to search")); + } + + private readonly modeToggle: ModeToggle; + private readonly findInput: FindInput; + private readonly actionbar: ActionBar; + private width = 0; + private right = 0; + + readonly _onDidDisable = new Emitter(); + readonly onDidDisable = this._onDidDisable.event; + readonly onDidChangeValue: Event; + readonly onDidChangeMode: Event; + + constructor( + container: HTMLElement, + private tree: AbstractTree, + contextViewProvider: IContextViewProvider, + mode: TreeFindMode, + options?: IFindWidgetOpts + ) { + super(); + + container.appendChild(this.elements.root); + this._register(toDisposable(() => container.removeChild(this.elements.root))); + + this.modeToggle = this._register(new ModeToggle({ ...options, isChecked: mode === TreeFindMode.Filter })); + this.onDidChangeMode = Event.map(this.modeToggle.onChange, () => this.modeToggle.checked ? TreeFindMode.Filter : TreeFindMode.Highlight, this._store); + + this.findInput = this._register(new FindInput(this.elements.findInput, contextViewProvider, { + label: localize('type to search', "Type to search"), + additionalToggles: [this.modeToggle], + showCommonFindToggles: false + })); + + this.actionbar = this._register(new ActionBar(this.elements.actionbar)); + this.mode = mode; + + const emitter = this._register(new DomEmitter(this.findInput.inputBox.inputElement, 'keydown')); + const onKeyDown = this._register(Event.chain(emitter.event)) + .map(e => new StandardKeyboardEvent(e)) + .event; + + this._register(onKeyDown((e): any => { + switch (e.keyCode) { + case KeyCode.DownArrow: + e.preventDefault(); + e.stopPropagation(); + this.tree.domFocus(); + return; + } + })); + + const closeAction = this._register(new Action('close', localize('close', "Close"), 'codicon codicon-close', true, () => this.dispose())); + this.actionbar.push(closeAction, { icon: true, label: false }); + + const onGrabMouseDown = this._register(new DomEmitter(this.elements.grab, 'mousedown')); + + this._register(onGrabMouseDown.event(e => { + const disposables = new DisposableStore(); + const onWindowMouseMove = disposables.add(new DomEmitter(window, 'mousemove')); + const onWindowMouseUp = disposables.add(new DomEmitter(window, 'mouseup')); + + const startRight = this.right; + const startX = e.pageX; + this.elements.grab.classList.add('grabbing'); + + const update = (e: MouseEvent) => { + const deltaX = e.pageX - startX; + this.right = startRight - deltaX; + this.layout(); + }; + + disposables.add(onWindowMouseMove.event(update)); + disposables.add(onWindowMouseUp.event(e => { + update(e); + this.elements.grab.classList.remove('grabbing'); + disposables.dispose(); + })); + })); + + const onGrabKeyDown = this._register(Event.chain(this._register(new DomEmitter(this.elements.grab, 'keydown')).event)) + .map(e => new StandardKeyboardEvent(e)) + .event; + + this._register(onGrabKeyDown((e): any => { + let right: number | undefined; + + if (e.keyCode === KeyCode.LeftArrow) { + right = Number.POSITIVE_INFINITY; + } else if (e.keyCode === KeyCode.RightArrow) { + right = 0; + } else if (e.keyCode === KeyCode.Space) { + right = this.right === 0 ? Number.POSITIVE_INFINITY : 0; + } + + if (right !== undefined) { + e.preventDefault(); + e.stopPropagation(); + this.right = right; + this.layout(); + } + })); + + this.onDidChangeValue = this.findInput.onDidChange; + this.style(options ?? {}); + } + + style(styles: IFindWidgetStyles): void { + this.findInput.style(styles); + + if (styles.listFilterWidgetBackground) { + this.elements.root.style.backgroundColor = styles.listFilterWidgetBackground.toString(); + } + + if (styles.listFilterWidgetShadow) { + this.elements.root.style.boxShadow = `0 0 8px 2px ${styles.listFilterWidgetShadow}`; + } + } + + focus() { + this.findInput.focus(); + } + + select() { + this.findInput.select(); + } + + layout(width: number = this.width): void { + this.width = width; + this.right = clamp(this.right, 0, Math.max(0, width - 212)); + this.elements.root.style.right = `${this.right}px`; + } + + showMessage(message: IMessage): void { + this.findInput.showMessage(message); + } + + clearMessage(): void { + this.findInput.clearMessage(); + } + + override async dispose(): Promise { + this._onDidDisable.fire(); + this.elements.root.classList.add('disabled'); + await timeout(300); + super.dispose(); + } +} + +class FindController implements IDisposable { private _pattern = ''; get pattern(): string { return this._pattern; } - private _filterOnType: boolean; - get filterOnType(): boolean { return this._filterOnType; } + private _mode: TreeFindMode; + get mode(): TreeFindMode { return this._mode; } + set mode(mode: TreeFindMode) { + if (mode === this._mode) { + return; + } - private _empty: boolean = false; - get empty(): boolean { return this._empty; } + this._mode = mode; - private readonly _onDidChangeEmptyState = new Emitter(); - readonly onDidChangeEmptyState: Event = Event.latch(this._onDidChangeEmptyState.event); + if (this.widget) { + this.widget.mode = this._mode; + } - private positionClassName = 'ne'; - private domNode: HTMLElement; - private messageDomNode: HTMLElement; - private labelDomNode: HTMLElement; - private filterOnTypeDomNode: HTMLInputElement; - private clearDomNode: HTMLElement; - private keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter; + this.tree.refilter(); + this.render(); + this._onDidChangeMode.fire(mode); + } - private automaticKeyboardNavigation = true; - private triggered = false; + private widget: FindWidget | undefined; + private styles: IFindWidgetStyles | undefined; + private width = 0; + + private readonly _onDidChangeMode = new Emitter(); + readonly onDidChangeMode = this._onDidChangeMode.event; private readonly _onDidChangePattern = new Emitter(); readonly onDidChangePattern = this._onDidChangePattern.event; - private readonly enabledDisposables = new DisposableStore(); + private readonly _onDidChangeOpenState = new Emitter(); + readonly onDidChangeOpenState = this._onDidChangeOpenState.event; + + private enabledDisposables = new DisposableStore(); private readonly disposables = new DisposableStore(); constructor( private tree: AbstractTree, model: ITreeModel, private view: List>, - private filter: TypeFilter, - private keyboardNavigationDelegate: IKeyboardNavigationDelegate + private filter: FindFilter, + private readonly contextViewProvider: IContextViewProvider ) { - this.domNode = $(`.monaco-list-type-filter.${this.positionClassName}`); - this.domNode.draggable = true; - this.disposables.add(addDisposableListener(this.domNode, 'dragstart', () => this.onDragStart())); - - this.messageDomNode = append(view.getHTMLElement(), $(`.monaco-list-type-filter-message`)); - - this.labelDomNode = append(this.domNode, $('span.label')); - const controls = append(this.domNode, $('.controls')); - - this._filterOnType = !!tree.options.filterOnType; - this.filterOnTypeDomNode = append(controls, $('input.filter')); - this.filterOnTypeDomNode.type = 'checkbox'; - this.filterOnTypeDomNode.checked = this._filterOnType; - this.filterOnTypeDomNode.tabIndex = -1; - this.updateFilterOnTypeTitleAndIcon(); - this.disposables.add(addDisposableListener(this.filterOnTypeDomNode, 'input', () => this.onDidChangeFilterOnType())); - - this.clearDomNode = append(controls, $('button.clear' + Codicon.treeFilterClear.cssSelector)); - this.clearDomNode.tabIndex = -1; - this.clearDomNode.title = localize('clear', "Clear"); - - this.keyboardNavigationEventFilter = tree.options.keyboardNavigationEventFilter; - + this._mode = tree.options.defaultFindMode ?? TreeFindMode.Highlight; model.onDidSplice(this.onDidSpliceModel, this, this.disposables); - this.updateOptions(tree.options); } - updateOptions(options: IAbstractTreeOptions): void { - if (options.simpleKeyboardNavigation) { - this.disable(); - } else { - this.enable(); - } - - if (typeof options.filterOnType !== 'undefined') { - this._filterOnType = !!options.filterOnType; - this.filterOnTypeDomNode.checked = this._filterOnType; - this.updateFilterOnTypeTitleAndIcon(); - } - - if (typeof options.automaticKeyboardNavigation !== 'undefined') { - this.automaticKeyboardNavigation = options.automaticKeyboardNavigation; - } - - this.tree.refilter(); - this.render(); - - if (!this.automaticKeyboardNavigation) { - this.onEventOrInput(''); - } - } - - toggle(): void { - this.triggered = !this.triggered; - - if (!this.triggered) { - this.onEventOrInput(''); - } - } - - private enable(): void { - if (this._enabled) { + open(): void { + if (this.widget) { + this.widget.focus(); + this.widget.select(); return; } - const onRawKeyDown = this.enabledDisposables.add(new DomEmitter(this.view.getHTMLElement(), 'keydown')); - const onKeyDown = Event.chain(onRawKeyDown.event) - .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) - .filter(e => (this.keyboardNavigationDelegate.mightProducePrintableCharacter(e) && !(e.keyCode === KeyCode.DownArrow || e.keyCode === KeyCode.UpArrow || e.keyCode === KeyCode.LeftArrow || e.keyCode === KeyCode.RightArrow)) || ((this.pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? (e.altKey && !e.metaKey) : e.ctrlKey) && !e.shiftKey))) - .forEach(e => { e.stopPropagation(); e.preventDefault(); }) - .event; + this.mode = this.tree.options.defaultFindMode ?? TreeFindMode.Highlight; + this.widget = new FindWidget(this.view.getHTMLElement(), this.tree, this.contextViewProvider, this.mode, this.styles); + this.enabledDisposables.add(this.widget); - const onClearClick = this.enabledDisposables.add(new DomEmitter(this.clearDomNode, 'click')); + this.widget.onDidChangeValue(this.onDidChangeValue, this, this.enabledDisposables); + this.widget.onDidChangeMode(mode => this.mode = mode, undefined, this.enabledDisposables); + this.widget.onDidDisable(this.close, this, this.enabledDisposables); - Event.chain(Event.any(onKeyDown, onClearClick.event)) - .event(this.onEventOrInput, this, this.enabledDisposables); + this.widget.layout(this.width); + this.widget.focus(); - this.filter.pattern = ''; - this.tree.refilter(); - this.render(); - this._enabled = true; - this.triggered = false; + this._onDidChangeOpenState.fire(true); } - private disable(): void { - if (!this._enabled) { + close(): void { + if (!this.widget) { return; } - this.domNode.remove(); - this.enabledDisposables.clear(); - this.tree.refilter(); - this.render(); - this._enabled = false; - this.triggered = false; + this.widget = undefined; + + this.enabledDisposables.dispose(); + this.enabledDisposables = new DisposableStore(); + + this.onDidChangeValue(''); + this.tree.domFocus(); + + this._onDidChangeOpenState.fire(false); } - private onEventOrInput(e: MouseEvent | StandardKeyboardEvent | string): void { - if (typeof e === 'string') { - this.onInput(e); - } else if (e instanceof MouseEvent || e.keyCode === KeyCode.Escape || (e.keyCode === KeyCode.Backspace && (isMacintosh ? e.altKey : e.ctrlKey))) { - this.onInput(''); - } else if (e.keyCode === KeyCode.Backspace) { - this.onInput(this.pattern.length === 0 ? '' : this.pattern.substr(0, this.pattern.length - 1)); - } else { - this.onInput(this.pattern + e.browserEvent.key); - } - } - - private onInput(pattern: string): void { - const container = this.view.getHTMLElement(); - - if (pattern && !this.domNode.parentElement) { - container.append(this.domNode); - } else if (!pattern && this.domNode.parentElement) { - this.domNode.remove(); - this.tree.domFocus(); - } - + private onDidChangeValue(pattern: string): void { this._pattern = pattern; this._onDidChangePattern.fire(pattern); @@ -836,75 +951,10 @@ class TypeFilterController implements IDisposable { } this.render(); - - if (!pattern) { - this.triggered = false; - } - } - - private onDragStart(): void { - const container = this.view.getHTMLElement(); - const { left } = getDomNodePagePosition(container); - const containerWidth = container.clientWidth; - const midContainerWidth = containerWidth / 2; - const width = this.domNode.clientWidth; - const disposables = new DisposableStore(); - let positionClassName = this.positionClassName; - - const updatePosition = () => { - switch (positionClassName) { - case 'nw': - this.domNode.style.top = `4px`; - this.domNode.style.left = `4px`; - break; - case 'ne': - this.domNode.style.top = `4px`; - this.domNode.style.left = `${containerWidth - width - 6}px`; - break; - } - }; - - const onDragOver = (event: DragEvent) => { - event.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome) - - const x = event.clientX - left; - if (event.dataTransfer) { - event.dataTransfer.dropEffect = 'none'; - } - - if (x < midContainerWidth) { - positionClassName = 'nw'; - } else { - positionClassName = 'ne'; - } - - updatePosition(); - }; - - const onDragEnd = () => { - this.positionClassName = positionClassName; - this.domNode.className = `monaco-list-type-filter ${this.positionClassName}`; - this.domNode.style.top = ''; - this.domNode.style.left = ''; - - dispose(disposables); - }; - - updatePosition(); - this.domNode.classList.remove(positionClassName); - - this.domNode.classList.add('dragging'); - disposables.add(toDisposable(() => this.domNode.classList.remove('dragging'))); - - disposables.add(addDisposableListener(document, 'dragover', e => onDragOver(e))); - disposables.add(addDisposableListener(this.domNode, 'dragend', () => onDragEnd())); - - StaticDND.CurrentDragAndDropData = new DragAndDropData('vscode-ui'); - disposables.add(toDisposable(() => StaticDND.CurrentDragAndDropData = undefined)); } private onDidSpliceModel(): void { - if (!this._enabled || this.pattern.length === 0) { + if (!this.widget || this.pattern.length === 0) { return; } @@ -912,46 +962,18 @@ class TypeFilterController implements IDisposable { this.render(); } - private onDidChangeFilterOnType(): void { - this.tree.updateOptions({ filterOnType: this.filterOnTypeDomNode.checked }); - this.tree.refilter(); - this.tree.domFocus(); - this.render(); - this.updateFilterOnTypeTitleAndIcon(); - } - - private updateFilterOnTypeTitleAndIcon(): void { - if (this.filterOnType) { - this.filterOnTypeDomNode.classList.remove(...Codicon.treeFilterOnTypeOff.classNamesArray); - this.filterOnTypeDomNode.classList.add(...Codicon.treeFilterOnTypeOn.classNamesArray); - this.filterOnTypeDomNode.title = localize('disable filter on type', "Disable Filter on Type"); - } else { - this.filterOnTypeDomNode.classList.remove(...Codicon.treeFilterOnTypeOn.classNamesArray); - this.filterOnTypeDomNode.classList.add(...Codicon.treeFilterOnTypeOff.classNamesArray); - this.filterOnTypeDomNode.title = localize('enable filter on type', "Enable Filter on Type"); - } - } - private render(): void { const noMatches = this.filter.totalCount > 0 && this.filter.matchCount === 0; - if (this.pattern && this.tree.options.filterOnType && noMatches) { - this.messageDomNode.textContent = localize('empty', "No elements found"); - this._empty = true; + if (this.pattern && noMatches) { + this.widget?.showMessage({ type: MessageType.WARNING, content: localize('not found', "No elements found.") }); } else { - this.messageDomNode.innerText = ''; - this._empty = false; + this.widget?.clearMessage(); } - - this.domNode.classList.toggle('no-matches', noMatches); - this.domNode.title = localize('found', "Matched {0} out of {1} elements", this.filter.matchCount, this.filter.totalCount); - this.labelDomNode.textContent = this.pattern.length > 16 ? '…' + this.pattern.substr(this.pattern.length - 16) : this.pattern; - - this._onDidChangeEmptyState.fire(this._empty); } shouldAllowFocus(node: ITreeNode): boolean { - if (!this.enabled || !this.pattern || this.filterOnType) { + if (!this.widget || !this.pattern || this._mode === TreeFindMode.Filter) { return true; } @@ -962,16 +984,20 @@ class TypeFilterController implements IDisposable { return !FuzzyScore.isDefault(node.filterData as any as FuzzyScore); } - dispose() { - if (this._enabled) { - this.domNode.remove(); - this.enabledDisposables.dispose(); - this._enabled = false; - this.triggered = false; - } + style(styles: IFindWidgetStyles): void { + this.styles = styles; + this.widget?.style(styles); + } + layout(width: number): void { + this.width = width; + this.widget?.layout(width); + } + + dispose() { this._onDidChangePattern.dispose(); - dispose(this.disposables); + this.enabledDisposables.dispose(); + this.disposables.dispose(); } } @@ -982,6 +1008,8 @@ function asTreeMouseEvent(event: IListMouseEvent>): ITreeMo target = TreeMouseEventTarget.Twistie; } else if (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tl-contents', 'monaco-tl-row')) { target = TreeMouseEventTarget.Element; + } else if (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tree-type-filter', 'monaco-list')) { + target = TreeMouseEventTarget.Filter; } return { @@ -999,15 +1027,11 @@ function asTreeContextMenuEvent(event: IListContextMenuEvent extends IAbstractTreeOptionsUpdate, IListOptions { + readonly contextViewProvider?: IContextViewProvider; readonly collapseByDefault?: boolean; // defaults to false readonly filter?: ITreeFilter; readonly dnd?: ITreeDragAndDrop; - readonly keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter; readonly additionalScrollHeight?: number; + readonly findWidgetEnabled?: boolean; } function dfs(node: ITreeNode, fn: (node: ITreeNode) => void): void { @@ -1153,7 +1178,9 @@ class TreeNodeListMouseController extends MouseController< } protected override onViewPointer(e: IListMouseEvent>): void { - if (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) { + if (isButton(e.browserEvent.target as HTMLElement) || + isInputElement(e.browserEvent.target as HTMLElement) || + isMonacoEditor(e.browserEvent.target as HTMLElement)) { return; } @@ -1316,7 +1343,8 @@ export abstract class AbstractTree implements IDisposable private selection: Trait; private anchor: Trait; private eventBufferer = new EventBufferer(); - private typeFilterController?: TypeFilterController; + private findController?: FindController; + readonly onDidChangeFindOpenState: Event = Event.None; private focusNavigationFilter: ((node: ITreeNode) => boolean) | undefined; private styleElement: HTMLStyleElement; protected readonly disposables = new DisposableStore(); @@ -1327,7 +1355,7 @@ export abstract class AbstractTree implements IDisposable get onDidChangeSelection(): Event> { return this.eventBufferer.wrapEvent(this.selection.onDidChange); } get onMouseClick(): Event> { return Event.map(this.view.onMouseClick, asTreeMouseEvent); } - get onMouseDblClick(): Event> { return Event.map(this.view.onMouseDblClick, asTreeMouseEvent); } + get onMouseDblClick(): Event> { return Event.filter(Event.map(this.view.onMouseDblClick, asTreeMouseEvent), e => e.target !== TreeMouseEventTarget.Filter); } get onContextMenu(): Event> { return Event.map(this.view.onContextMenu, asTreeContextMenuEvent); } get onTap(): Event> { return Event.map(this.view.onTap, asTreeMouseEvent); } get onPointer(): Event> { return Event.map(this.view.onPointer, asTreeMouseEvent); } @@ -1346,8 +1374,11 @@ export abstract class AbstractTree implements IDisposable private readonly _onWillRefilter = new Emitter(); readonly onWillRefilter: Event = this._onWillRefilter.event; - get filterOnType(): boolean { return !!this._options.filterOnType; } - get onDidChangeTypeFilterPattern(): Event { return this.typeFilterController ? this.typeFilterController.onDidChangePattern : Event.None; } + get findMode(): TreeFindMode { return this.findController?.mode ?? TreeFindMode.Highlight; } + set findMode(findMode: TreeFindMode) { if (this.findController) { this.findController.mode = findMode; } } + readonly onDidChangeFindMode: Event; + + get onDidChangeFindPattern(): Event { return this.findController ? this.findController.onDidChangePattern : Event.None; } get expandOnDoubleClick(): boolean { return typeof this._options.expandOnDoubleClick === 'undefined' ? true : this._options.expandOnDoubleClick; } get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? true : this._options.expandOnlyOnTwistieClick; } @@ -1374,10 +1405,10 @@ export abstract class AbstractTree implements IDisposable this.disposables.add(r); } - let filter: TypeFilter | undefined; + let filter: FindFilter | undefined; if (_options.keyboardNavigationLabelProvider) { - filter = new TypeFilter(this, _options.keyboardNavigationLabelProvider, _options.filter as any as ITreeFilter); + filter = new FindFilter(this, _options.keyboardNavigationLabelProvider, _options.filter as any as ITreeFilter); _options = { ..._options, filter: filter as ITreeFilter }; // TODO need typescript help here this.disposables.add(filter); } @@ -1430,11 +1461,14 @@ export abstract class AbstractTree implements IDisposable onKeyDown.filter(e => e.keyCode === KeyCode.Space).on(this.onSpace, this, this.disposables); } - if (_options.keyboardNavigationLabelProvider) { - 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.add(this.typeFilterController!); + if ((_options.findWidgetEnabled ?? true) && _options.keyboardNavigationLabelProvider && _options.contextViewProvider) { + this.findController = new FindController(this, this.model, this.view, filter!, _options.contextViewProvider); + this.focusNavigationFilter = node => this.findController!.shouldAllowFocus(node); + this.onDidChangeFindOpenState = this.findController.onDidChangeOpenState; + this.disposables.add(this.findController!); + this.onDidChangeFindMode = this.findController.onDidChangeMode; + } else { + this.onDidChangeFindMode = Event.None; } this.styleElement = createStyleSheet(this.view.getHTMLElement()); @@ -1448,13 +1482,7 @@ export abstract class AbstractTree implements IDisposable renderer.updateOptions(optionsUpdate); } - this.view.updateOptions({ - ...this._options, - enableKeyboardNavigation: this._options.simpleKeyboardNavigation, - }); - - this.typeFilterController?.updateOptions(this._options); - + this.view.updateOptions(this._options); this._onDidUpdateOptions.fire(this._options); this.getHTMLElement().classList.toggle('always', this._options.renderIndentGuides === RenderIndentGuides.Always); @@ -1481,21 +1509,11 @@ export abstract class AbstractTree implements IDisposable } get contentHeight(): number { - if (this.typeFilterController && this.typeFilterController.filterOnType && this.typeFilterController.empty) { - return 100; - } - return this.view.contentHeight; } get onDidChangeContentHeight(): Event { - let result = this.view.onDidChangeContentHeight; - - if (this.typeFilterController) { - result = Event.any(result, Event.map(this.typeFilterController.onDidChangeEmptyState, () => this.contentHeight)); - } - - return result; + return this.view.onDidChangeContentHeight; } get scrollTop(): number { @@ -1557,6 +1575,10 @@ export abstract class AbstractTree implements IDisposable layout(height?: number, width?: number): void { this.view.layout(height, width); + + if (isNumber(width)) { + this.findController?.layout(width); + } } style(styles: IListStyles): void { @@ -1569,6 +1591,8 @@ export abstract class AbstractTree implements IDisposable } this.styleElement.textContent = content.join('\n'); + + this.findController?.style(styles); this.view.style(styles); } @@ -1622,12 +1646,16 @@ export abstract class AbstractTree implements IDisposable return this.model.isCollapsed(location); } - toggleKeyboardNavigation(): void { - this.view.toggleKeyboardNavigation(); + triggerTypeNavigation(): void { + this.view.triggerTypeNavigation(); + } - if (this.typeFilterController) { - this.typeFilterController.toggle(); - } + openFind(): void { + this.findController?.open(); + } + + closeFind(): void { + this.findController?.close(); } refilter(): void { diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 64b6abe79ce..a8b84679303 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -7,7 +7,7 @@ import { IDragAndDropData } from 'vs/base/browser/dnd'; import { IIdentityProvider, IListDragAndDrop, IListDragOverReaction, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { IListStyles } from 'vs/base/browser/ui/list/listWidget'; -import { ComposedTreeDelegate, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree'; +import { ComposedTreeDelegate, TreeFindMode as TreeFindMode, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree'; import { ICompressedTreeElement, ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; import { getVisibleState, isFilterResult } from 'vs/base/browser/ui/tree/indexTreeModel'; import { CompressibleObjectTree, ICompressibleKeyboardNavigationLabelProvider, ICompressibleObjectTreeOptions, ICompressibleTreeRenderer, IObjectTreeOptions, IObjectTreeSetChildrenOptions, ObjectTree } from 'vs/base/browser/ui/tree/objectTree'; @@ -341,7 +341,12 @@ export class AsyncDataTree implements IDisposable get onDidUpdateOptions(): Event { return this.tree.onDidUpdateOptions; } - get filterOnType(): boolean { return this.tree.filterOnType; } + get onDidChangeFindOpenState(): Event { return this.tree.onDidChangeFindOpenState; } + + get findMode(): TreeFindMode { return this.tree.findMode; } + set findMode(mode: TreeFindMode) { this.tree.findMode = mode; } + readonly onDidChangeFindMode: Event; + get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { if (typeof this.tree.expandOnlyOnTwistieClick === 'boolean') { return this.tree.expandOnlyOnTwistieClick; @@ -367,6 +372,7 @@ export class AsyncDataTree implements IDisposable this.collapseByDefault = options.collapseByDefault; this.tree = this.createTree(user, container, delegate, renderers, options); + this.onDidChangeFindMode = this.tree.onDidChangeFindMode; this.root = createAsyncDataTreeNode({ element: undefined!, @@ -616,8 +622,16 @@ export class AsyncDataTree implements IDisposable return this.tree.isCollapsed(this.getDataNode(element)); } - toggleKeyboardNavigation(): void { - this.tree.toggleKeyboardNavigation(); + triggerTypeNavigation(): void { + this.tree.triggerTypeNavigation(); + } + + openFind(): void { + this.tree.openFind(); + } + + closeFind(): void { + this.tree.closeFind(); } refilter(): void { @@ -728,6 +742,16 @@ export class AsyncDataTree implements IDisposable return result; } + if (node !== this.root) { + const treeNode = this.tree.getNode(node); + + if (treeNode.collapsed) { + node.hasChildren = !!this.dataSource.hasChildren(node.element!); + node.stale = true; + return; + } + } + return this.doRefreshSubTree(node, recursive, viewStateContext); } diff --git a/src/vs/base/browser/ui/tree/media/tree.css b/src/vs/base/browser/ui/tree/media/tree.css index 22f0d23bf60..bee620d57ef 100644 --- a/src/vs/base/browser/ui/tree/media/tree.css +++ b/src/vs/base/browser/ui/tree/media/tree.css @@ -10,6 +10,9 @@ position: relative; } +.monaco-tl-row.disabled { + cursor: default; +} .monaco-tl-indent { height: 100%; position: absolute; @@ -67,3 +70,55 @@ /* Use steps to throttle FPS to reduce CPU usage */ animation: codicon-spin 1.25s steps(30) infinite; } + +.monaco-tree-type-filter { + position: absolute; + top: 0; + display: flex; + padding: 3px; + transition: top 0.3s; + max-width: 200px; + z-index: 100; + margin: 0 6px; +} + +.monaco-tree-type-filter.disabled { + top: -40px; +} + +.monaco-tree-type-filter-grab { + display: flex !important; + align-items: center; + justify-content: center; + cursor: grab; + margin-right: 2px; +} + +.monaco-tree-type-filter-grab.grabbing { + cursor: grabbing; +} + +.monaco-tree-type-filter-input { + flex: 1; +} + +.monaco-tree-type-filter-input .monaco-inputbox { + height: 23px; +} + +.monaco-tree-type-filter-input .monaco-inputbox > .ibwrapper > .input, +.monaco-tree-type-filter-input .monaco-inputbox > .ibwrapper > .mirror { + padding: 2px 4px; +} + +.monaco-tree-type-filter-input .monaco-findInput > .controls { + top: 2px; +} + +.monaco-tree-type-filter-actionbar { + margin-left: 4px; +} + +.monaco-tree-type-filter-actionbar .monaco-action-bar .action-label { + padding: 2px; +} diff --git a/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts index 0166e4cd3b6..f29091c104a 100644 --- a/src/vs/base/browser/ui/tree/tree.ts +++ b/src/vs/base/browser/ui/tree/tree.ts @@ -141,7 +141,8 @@ export interface ITreeEvent { export enum TreeMouseEventTarget { Unknown, Twistie, - Element + Element, + Filter } export interface ITreeMouseEvent { diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index f9729a18770..ba45db870fe 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -15,8 +15,9 @@ export interface ITelemetryData { export type WorkbenchActionExecutedClassification = { owner: 'bpasero'; - id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; - from: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; + comment: 'TODO @bpasero'; + id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier of the action that was run.' }; + from: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The name of the component the action was run from.' }; }; export type WorkbenchActionExecutedEvent = { @@ -24,7 +25,7 @@ export type WorkbenchActionExecutedEvent = { from: string; }; -export interface IAction extends IDisposable { +export interface IAction { readonly id: string; label: string; tooltip: string; @@ -241,12 +242,6 @@ export class SubmenuAction implements IAction { this._actions = actions; } - dispose(): void { - // there is NOTHING to dispose and the SubmenuAction should - // never have anything to dispose as it is a convenience type - // to bridge into the rendering world. - } - async run(): Promise { } } @@ -267,7 +262,6 @@ export function toAction(props: { id: string; label: string; enabled?: boolean; enabled: props.enabled ?? true, checked: props.checked ?? false, run: async () => props.run(), - tooltip: props.label, - dispose: () => { } + tooltip: props.label }; } diff --git a/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts index b567c8fe977..2457de74f0b 100644 --- a/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -46,6 +46,18 @@ export function equals(one: ReadonlyArray | undefined, other: ReadonlyArra return true; } +/** + * Remove the element at `index` by replacing it with the last element. This is faster than `splice` + * but changes the order of the array + */ +export function removeFastWithoutKeepingOrder(array: T[], index: number) { + const last = array.length - 1; + if (index < last) { + array[index] = array[last]; + } + array.pop(); +} + /** * Performs a binary search algorithm over a sorted array. * @@ -817,3 +829,79 @@ export class ArrayQueue { return result; } } + +/** + * This class is faster than an iterator and array for lazy computed data. +*/ +export class CallbackIterable { + public static readonly empty = new CallbackIterable(_callback => { }); + + constructor( + /** + * Calls the callback for every item. + * Stops when the callback returns false. + */ + public readonly iterate: (callback: (item: T) => boolean) => void + ) { + } + + forEach(handler: (item: T) => void) { + this.iterate(item => { handler(item); return true; }); + } + + toArray(): T[] { + const result: T[] = []; + this.iterate(item => { result.push(item); return true; }); + return result; + } + + filter(predicate: (item: T) => boolean): CallbackIterable { + return new CallbackIterable(cb => this.iterate(item => predicate(item) ? cb(item) : true)); + } + + map(mapFn: (item: T) => TResult): CallbackIterable { + return new CallbackIterable(cb => this.iterate(item => cb(mapFn(item)))); + } + + some(predicate: (item: T) => boolean): boolean { + let result = false; + this.iterate(item => { result = predicate(item); return !result; }); + return result; + } + + findFirst(predicate: (item: T) => boolean): T | undefined { + let result: T | undefined; + this.iterate(item => { + if (predicate(item)) { + result = item; + return false; + } + return true; + }); + return result; + } + + findLast(predicate: (item: T) => boolean): T | undefined { + let result: T | undefined; + this.iterate(item => { + if (predicate(item)) { + result = item; + } + return true; + }); + return result; + } + + findLastMaxBy(comparator: Comparator): T | undefined { + let result: T | undefined; + let first = true; + this.iterate(item => { + if (first || CompareResult.isGreaterThan(comparator(item, result!))) { + first = false; + result = item; + } + return true; + }); + return result; + } +} diff --git a/src/vs/base/common/assert.ts b/src/vs/base/common/assert.ts index 9e2510b4d0b..5efd7244ff4 100644 --- a/src/vs/base/common/assert.ts +++ b/src/vs/base/common/assert.ts @@ -3,11 +3,60 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { BugIndicatingError, onUnexpectedError } from 'vs/base/common/errors'; + /** * Throws an error with the provided message if the provided value does not evaluate to a true Javascript value. + * + * @deprecated Use `assert(...)` instead. + * This method is usually used like this: + * ```ts + * import * as assert from 'vs/base/common/assert'; + * assert.ok(...); + * ``` + * + * However, `assert` in that example is a user chosen name. + * There is no tooling for generating such an import statement. + * Thus, the `assert(...)` function should be used instead. */ export function ok(value?: unknown, message?: string) { if (!value) { throw new Error(message ? `Assertion failed (${message})` : 'Assertion Failed'); } } + +export function assertNever(value: never, message = 'Unreachable'): never { + throw new Error(message); +} + +export function assert(condition: boolean): void { + if (!condition) { + throw new BugIndicatingError('Assertion Failed'); + } +} + +/** + * condition must be side-effect free! + */ +export function assertFn(condition: () => boolean): void { + if (!condition()) { + // eslint-disable-next-line no-debugger + debugger; + // Reevaluate `condition` again to make debugging easier + condition(); + onUnexpectedError(new BugIndicatingError('Assertion Failed')); + } +} + +export function checkAdjacentItems(items: readonly T[], predicate: (item1: T, item2: T) => boolean): boolean { + let i = 0; + while (i < items.length - 1) { + const a = items[i]; + const b = items[i + 1]; + if (!predicate(a, b)) { + return false; + } + i++; + } + return true; +} diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index e45c78ae5e3..f4f79545b3a 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -1227,15 +1227,15 @@ export async function retry(task: ITask>, delay: number, retries: //#region Task Sequentializer interface IPendingTask { - taskId: number; - cancel: () => void; - promise: Promise; + readonly taskId: number; + readonly cancel: () => void; + readonly promise: Promise; } -interface ISequentialTask { - promise: Promise; - promiseResolve: () => void; - promiseReject: (error: Error) => void; +interface INextTask { + readonly promise: Promise; + readonly promiseResolve: () => void; + readonly promiseReject: (error: Error) => void; run: () => Promise; } @@ -1243,9 +1243,14 @@ export interface ITaskSequentializerWithPendingTask { readonly pending: Promise; } +export interface ITaskSequentializerWithNextTask { + readonly next: INextTask; +} + export class TaskSequentializer { + private _pending?: IPendingTask; - private _next?: ISequentialTask; + private _next?: INextTask; hasPending(taskId?: number): this is ITaskSequentializerWithPendingTask { if (!this._pending) { @@ -1260,7 +1265,7 @@ export class TaskSequentializer { } get pending(): Promise | undefined { - return this._pending ? this._pending.promise : undefined; + return this._pending?.promise; } cancelPending(): void { @@ -1324,6 +1329,14 @@ export class TaskSequentializer { return this._next.promise; } + + hasNext(): this is ITaskSequentializerWithNextTask { + return !!this._next; + } + + async join(): Promise { + return this._next?.promise ?? this._pending?.promise; + } } //#endregion @@ -1389,7 +1402,7 @@ export class DeferredPromise { return this.rejected || this.resolved; } - public p: Promise; + public readonly p: Promise; constructor() { this.p = new Promise((c, e) => { diff --git a/src/vs/base/common/cancellation.ts b/src/vs/base/common/cancellation.ts index 9cc02257cab..78e01b75ec1 100644 --- a/src/vs/base/common/cancellation.ts +++ b/src/vs/base/common/cancellation.ts @@ -129,9 +129,7 @@ export class CancellationTokenSource { if (cancel) { this.cancel(); } - if (this._parentListener) { - this._parentListener.dispose(); - } + this._parentListener?.dispose(); if (!this._token) { // ensure to initialize with an empty token if we had none this._token = CancellationToken.None; diff --git a/src/vs/base/common/codicons.ts b/src/vs/base/common/codicons.ts index 9e696833141..9d60df36d53 100644 --- a/src/vs/base/common/codicons.ts +++ b/src/vs/base/common/codicons.ts @@ -94,11 +94,11 @@ export class Codicon implements CSSIcon { public static readonly eyeUnwatch = new Codicon('eye-unwatch', { fontCharacter: '\\ea70' }); public static readonly eyeWatch = new Codicon('eye-watch', { fontCharacter: '\\ea70' }); public static readonly circleFilled = new Codicon('circle-filled', { fontCharacter: '\\ea71' }); - public static readonly primitiveDot = new Codicon('primitive-dot', { fontCharacter: '\\ea71' }); - public static readonly closeDirty = new Codicon('close-dirty', { fontCharacter: '\\ea71' }); - public static readonly debugBreakpoint = new Codicon('debug-breakpoint', { fontCharacter: '\\ea71' }); - public static readonly debugBreakpointDisabled = new Codicon('debug-breakpoint-disabled', { fontCharacter: '\\ea71' }); - public static readonly debugHint = new Codicon('debug-hint', { fontCharacter: '\\ea71' }); + public static readonly primitiveDot = new Codicon('primitive-dot', Codicon.circleFilled.definition); + public static readonly closeDirty = new Codicon('close-dirty', Codicon.circleFilled.definition); + public static readonly debugBreakpoint = new Codicon('debug-breakpoint', Codicon.circleFilled.definition); + public static readonly debugBreakpointDisabled = new Codicon('debug-breakpoint-disabled', Codicon.circleFilled.definition); + public static readonly debugHint = new Codicon('debug-hint', Codicon.circleFilled.definition); public static readonly primitiveSquare = new Codicon('primitive-square', { fontCharacter: '\\ea72' }); public static readonly edit = new Codicon('edit', { fontCharacter: '\\ea73' }); public static readonly pencil = new Codicon('pencil', { fontCharacter: '\\ea73' }); @@ -218,8 +218,9 @@ export class Codicon implements CSSIcon { public static readonly chromeMaximize = new Codicon('chrome-maximize', { fontCharacter: '\\eab9' }); public static readonly chromeMinimize = new Codicon('chrome-minimize', { fontCharacter: '\\eaba' }); public static readonly chromeRestore = new Codicon('chrome-restore', { fontCharacter: '\\eabb' }); - public static readonly circleOutline = new Codicon('circle-outline', { fontCharacter: '\\eabc' }); - public static readonly debugBreakpointUnverified = new Codicon('debug-breakpoint-unverified', { fontCharacter: '\\eabc' }); + public static readonly circle = new Codicon('circle', { fontCharacter: '\\eabc' }); + public static readonly circleOutline = new Codicon('circle-outline', Codicon.circle.definition); + public static readonly debugBreakpointUnverified = new Codicon('debug-breakpoint-unverified', Codicon.circle.definition); public static readonly circleSlash = new Codicon('circle-slash', { fontCharacter: '\\eabd' }); public static readonly circuitBoard = new Codicon('circuit-board', { fontCharacter: '\\eabe' }); public static readonly clearAll = new Codicon('clear-all', { fontCharacter: '\\eabf' }); @@ -473,7 +474,8 @@ export class Codicon implements CSSIcon { public static readonly pinnedDirty = new Codicon('pinned-dirty', { fontCharacter: '\\ebb2' }); public static readonly passFilled = new Codicon('pass-filled', { fontCharacter: '\\ebb3' }); public static readonly circleLargeFilled = new Codicon('circle-large-filled', { fontCharacter: '\\ebb4' }); - public static readonly circleLargeOutline = new Codicon('circle-large-outline', { fontCharacter: '\\ebb5' }); + public static readonly circleLarge = new Codicon('circle-large', { fontCharacter: '\\ebb5' }); + public static readonly circleLargeOutline = new Codicon('circle-large-outline', Codicon.circleLarge.definition); public static readonly combine = new Codicon('combine', { fontCharacter: '\\ebb6' }); public static readonly gather = new Codicon('gather', { fontCharacter: '\\ebb6' }); public static readonly table = new Codicon('table', { fontCharacter: '\\ebb7' }); @@ -558,7 +560,11 @@ export class Codicon implements CSSIcon { public static readonly mapFilled = new Codicon('map-filled', { fontCharacter: '\\ec06' }); public static readonly circleSmall = new Codicon('circle-small', { fontCharacter: '\\ec07' }); public static readonly bellSlash = new Codicon('bell-slash', { fontCharacter: '\\ec08' }); - public static readonly bellSlashDot = new Codicon('bell-slash-dot', { fontCharacter: '\\f101' }); + public static readonly bellSlashDot = new Codicon('bell-slash-dot', { fontCharacter: '\\ec09' }); + public static readonly commentUnresolved = new Codicon('comment-unresolved', { fontCharacter: '\\ec0a' }); + public static readonly gitPullRequestGoToChanges = new Codicon('git-pull-request-go-to-changes', { fontCharacter: '\\ec0b' }); + public static readonly gitPullRequestNewChanges = new Codicon('git-pull-request-new-changes', { fontCharacter: '\\ec0c' }); + public static readonly searchFuzzy = new Codicon('search-fuzzy', { fontCharacter: '\\ec0d' }); // derived icons, that could become separate icons diff --git a/src/vs/base/common/collections.ts b/src/vs/base/common/collections.ts index 1f16cd438ea..d8ee92f757e 100644 --- a/src/vs/base/common/collections.ts +++ b/src/vs/base/common/collections.ts @@ -15,20 +15,6 @@ export type IStringDictionary = Record; */ export type INumberDictionary = Record; -/** - * Iterates over each entry in the provided dictionary. The iterator will stop when the callback returns `false`. - * - * @deprecated Use `Object.entries(x)` with a `for...of` loop. - */ -export function forEach(from: IStringDictionary | INumberDictionary, callback: (entry: { key: any; value: T }) => any): void { - for (const [key, value] of Object.entries(from)) { - const result = callback({ key, value }); - if (result === false) { - return; - } - } -} - /** * Groups the collection into a dictionary based on the provided * group function. diff --git a/src/vs/base/common/dataTransfer.ts b/src/vs/base/common/dataTransfer.ts index 5074f30c75e..a65c4938fc4 100644 --- a/src/vs/base/common/dataTransfer.ts +++ b/src/vs/base/common/dataTransfer.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; export interface IDataTransferFile { readonly name: string; @@ -12,6 +13,7 @@ export interface IDataTransferFile { } export interface IDataTransferItem { + readonly id: string; asString(): Thenable; asFile(): IDataTransferFile | undefined; value: any; @@ -19,6 +21,7 @@ export interface IDataTransferItem { export function createStringDataTransferItem(stringOrPromise: string | Promise): IDataTransferItem { return { + id: generateUuid(), asString: async () => stringOrPromise, asFile: () => undefined, value: typeof stringOrPromise === 'string' ? stringOrPromise : undefined, @@ -27,6 +30,7 @@ export function createStringDataTransferItem(stringOrPromise: string | Promise Promise): IDataTransferItem { return { + id: generateUuid(), asString: async () => '', asFile: () => ({ name: fileName, uri, data }), value: undefined, diff --git a/src/vs/base/common/errors.ts b/src/vs/base/common/errors.ts index 9ea8d9f394e..44b25af9e3a 100644 --- a/src/vs/base/common/errors.ts +++ b/src/vs/base/common/errors.ts @@ -243,7 +243,7 @@ export class ErrorNoTelemetry extends Error { constructor(msg?: string) { super(msg); - this.name = 'ErrorNoTelemetry'; + this.name = 'CodeExpectedError'; } public static fromError(err: Error): ErrorNoTelemetry { @@ -258,7 +258,7 @@ export class ErrorNoTelemetry extends Error { } public static isErrorNoTelemetry(err: Error): err is ErrorNoTelemetry { - return err.name === 'ErrorNoTelemetry'; + return err.name === 'CodeExpectedError'; } } diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 647b5f1beed..054cf4de2d4 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -8,6 +8,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { once as onceFn } from 'vs/base/common/functional'; import { combinedDisposable, Disposable, DisposableStore, IDisposable, SafeDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; +import { IObservable, IObserver } from 'vs/base/common/observable'; import { StopWatch } from 'vs/base/common/stopwatch'; @@ -423,6 +424,55 @@ export namespace Event { store?.dispose(); }); } + + class EmitterObserver implements IObserver { + + readonly emitter: Emitter; + + private _counter = 0; + private _hasChanged = false; + + constructor(readonly obs: IObservable, store: DisposableStore | undefined) { + const options = { + onFirstListenerAdd: () => { + obs.addObserver(this); + }, + onLastListenerRemove: () => { + obs.removeObserver(this); + } + }; + if (!store) { + _addLeakageTraceLogic(options); + } + this.emitter = new Emitter(options); + if (store) { + store.add(this.emitter); + } + } + + beginUpdate(_observable: IObservable): void { + // console.assert(_observable === this.obs); + this._counter++; + } + + handleChange(_observable: IObservable, _change: TChange): void { + this._hasChanged = true; + } + + endUpdate(_observable: IObservable): void { + if (--this._counter === 0) { + if (this._hasChanged) { + this._hasChanged = false; + this.emitter.fire(this.obs.get()); + } + } + } + } + + export function fromObservable(obs: IObservable, store?: DisposableStore): Event { + const observer = new EmitterObserver(obs, store); + return observer.emitter.event; + } } export interface EmitterOptions { @@ -742,7 +792,7 @@ export class Emitter { if (!this._listeners) { return false; } - return (!this._listeners.isEmpty()); + return !this._listeners.isEmpty(); } } @@ -944,6 +994,11 @@ export class MicrotaskEmitter extends Emitter { this._mergeFn = options?.merge; } override fire(event: T): void { + + if (!this.hasListeners()) { + return; + } + this._queuedEvents.push(event); if (this._queuedEvents.length === 1) { queueMicrotask(() => { diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index d0a8a09aa70..ebad3f5805d 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -316,7 +316,18 @@ function _matchesWords(word: string, target: string, i: number, j: number, conti nextWordIndex++; } } - return result === null ? null : join({ start: j, end: j + 1 }, result); + + if (!result) { + return null; + } + + // If the characters don't exactly match, then they must be word separators (see charactersMatch(...)). + // We don't want to include this in the matches but we don't want to throw the target out all together so we return `result`. + if (word.charCodeAt(i) !== target.charCodeAt(j)) { + return result; + } + + return join({ start: j, end: j + 1 }, result); } } diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index ab2458bc061..da910eb4e77 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -108,14 +108,6 @@ export function markAsSingleton(singleton: T): T { return singleton; } -export class MultiDisposeError extends Error { - constructor( - public readonly errors: any[] - ) { - super(`Encountered errors while disposing of store. Errors: [${errors.join(', ')}]`); - } -} - export interface IDisposable { dispose(): void; } @@ -146,7 +138,7 @@ export function dispose(arg: T | IterableIterator | un if (errors.length === 1) { throw errors[0]; } else if (errors.length > 1) { - throw new MultiDisposeError(errors); + throw new AggregateError(errors, 'Encountered errors while disposing of store'); } return Array.isArray(arg) ? [] : arg; @@ -156,6 +148,14 @@ export function dispose(arg: T | IterableIterator | un } } +export function disposeIfDisposable(disposables: Array): Array { + for (const d of disposables) { + if (isDisposable(d)) { + d.dispose(); + } + } + return []; +} export function combinedDisposable(...disposables: IDisposable[]): IDisposable { const parent = toDisposable(() => dispose(disposables)); diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 4b153336f01..2a78f7afb18 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -715,22 +715,28 @@ export class TernarySearchTree { yield* this._entries(this._root); } - private *_entries(node: TernarySearchTreeNode | undefined): IterableIterator<[K, V]> { + private _entries(node: TernarySearchTreeNode | undefined): IterableIterator<[K, V]> { + const result: [K, V][] = []; + this._dfsEntries(node, result); + return result[Symbol.iterator](); + } + + private _dfsEntries(node: TernarySearchTreeNode | undefined, bucket: [K, V][]) { // DFS if (!node) { return; } if (node.left) { - yield* this._entries(node.left); + this._dfsEntries(node.left, bucket); } if (node.value) { - yield [node.key!, node.value]; + bucket.push([node.key!, node.value]); } if (node.mid) { - yield* this._entries(node.mid); + this._dfsEntries(node.mid, bucket); } if (node.right) { - yield* this._entries(node.right); + this._dfsEntries(node.right, bucket); } } @@ -1349,47 +1355,3 @@ export class LRUCache extends LinkedMap { } } } - -/** - * Wraps the map in type that only implements readonly properties. Useful - * in the extension host to prevent the consumer from making any mutations. - */ -export class ReadonlyMapView implements ReadonlyMap{ - readonly #source: ReadonlyMap; - - public get size() { - return this.#source.size; - } - - constructor(source: ReadonlyMap) { - this.#source = source; - } - - forEach(callbackfn: (value: V, key: K, map: ReadonlyMap) => void, thisArg?: any): void { - this.#source.forEach(callbackfn, thisArg); - } - - get(key: K): V | undefined { - return this.#source.get(key); - } - - has(key: K): boolean { - return this.#source.has(key); - } - - entries(): IterableIterator<[K, V]> { - return this.#source.entries(); - } - - keys(): IterableIterator { - return this.#source.keys(); - } - - values(): IterableIterator { - return this.#source.values(); - } - - [Symbol.iterator](): IterableIterator<[K, V]> { - return this.#source.entries(); - } -} diff --git a/src/vs/base/common/marked/cgmanifest.json b/src/vs/base/common/marked/cgmanifest.json index 60e11b4144e..4dffc3ff231 100644 --- a/src/vs/base/common/marked/cgmanifest.json +++ b/src/vs/base/common/marked/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "marked", "repositoryUrl": "https://github.com/markedjs/marked", - "commitHash": "2002557d004139ca2208c910d9ca999829b65406" + "commitHash": "7e2ef307846427650114591f9257b5545868e928" } }, "license": "MIT", - "version": "4.0.16" + "version": "4.1.0" } ], "version": 1 diff --git a/src/vs/base/common/marked/marked.d.ts b/src/vs/base/common/marked/marked.d.ts index 5b7014ec2fb..7aeab2e864d 100644 --- a/src/vs/base/common/marked/marked.d.ts +++ b/src/vs/base/common/marked/marked.d.ts @@ -10,6 +10,8 @@ // Sarun Intaralawan // Tony Brix // Anatolii Titov +// Jean-Francois Cere +// Mykhaylo Stolyarchuk // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped /** @@ -75,11 +77,7 @@ export namespace marked { * @param callback Function called when the markdownString has been fully parsed when using async highlighting * @return String of compiled HTML */ - function parse( - src: string, - options?: MarkedOptions, - callback?: (error: any, parseResult: string) => void, - ): string; + function parse(src: string, options?: MarkedOptions, callback?: (error: any, parseResult: string) => void): string; /** * @param src Tokenized source as array of tokens @@ -126,34 +124,39 @@ export namespace marked { class Tokenizer { constructor(options?: MarkedOptions); options: MarkedOptions; - space(this: TokenizerThis, src: string): Tokens.Space | T; - code(this: TokenizerThis, src: string): Tokens.Code | T; - fences(this: TokenizerThis, src: string): Tokens.Code | T; - heading(this: TokenizerThis, src: string): Tokens.Heading | T; - hr(this: TokenizerThis, src: string): Tokens.Hr | T; - blockquote(this: TokenizerThis, src: string): Tokens.Blockquote | T; - list(this: TokenizerThis, src: string): Tokens.List | T; - html(this: TokenizerThis, src: string): Tokens.HTML | T; - def(this: TokenizerThis, src: string): Tokens.Def | T; - table(this: TokenizerThis, src: string): Tokens.Table | T; - lheading(this: TokenizerThis, src: string): Tokens.Heading | T; - paragraph(this: TokenizerThis, src: string): Tokens.Paragraph | T; - text(this: TokenizerThis, src: string): Tokens.Text | T; - escape(this: TokenizerThis, src: string): Tokens.Escape | T; - tag(this: TokenizerThis, src: string): Tokens.Tag | T; - link(this: TokenizerThis, src: string): Tokens.Image | Tokens.Link | T; + space(this: Tokenizer & TokenizerThis, src: string): Tokens.Space | T; + code(this: Tokenizer & TokenizerThis, src: string): Tokens.Code | T; + fences(this: Tokenizer & TokenizerThis, src: string): Tokens.Code | T; + heading(this: Tokenizer & TokenizerThis, src: string): Tokens.Heading | T; + hr(this: Tokenizer & TokenizerThis, src: string): Tokens.Hr | T; + blockquote(this: Tokenizer & TokenizerThis, src: string): Tokens.Blockquote | T; + list(this: Tokenizer & TokenizerThis, src: string): Tokens.List | T; + html(this: Tokenizer & TokenizerThis, src: string): Tokens.HTML | T; + def(this: Tokenizer & TokenizerThis, src: string): Tokens.Def | T; + table(this: Tokenizer & TokenizerThis, src: string): Tokens.Table | T; + lheading(this: Tokenizer & TokenizerThis, src: string): Tokens.Heading | T; + paragraph(this: Tokenizer & TokenizerThis, src: string): Tokens.Paragraph | T; + text(this: Tokenizer & TokenizerThis, src: string): Tokens.Text | T; + escape(this: Tokenizer & TokenizerThis, src: string): Tokens.Escape | T; + tag(this: Tokenizer & TokenizerThis, src: string): Tokens.Tag | T; + link(this: Tokenizer & TokenizerThis, src: string): Tokens.Image | Tokens.Link | T; reflink( - this: TokenizerThis, + this: Tokenizer & TokenizerThis, src: string, links: Tokens.Link[] | Tokens.Image[], ): Tokens.Link | Tokens.Image | Tokens.Text | T; - emStrong(this: TokenizerThis, src: string, maskedSrc: string, prevChar: string): Tokens.Em | Tokens.Strong | T; - codespan(this: TokenizerThis, src: string): Tokens.Codespan | T; - br(this: TokenizerThis, src: string): Tokens.Br | T; - del(this: TokenizerThis, src: string): Tokens.Del | T; - autolink(this: TokenizerThis, src: string, mangle: (cap: string) => string): Tokens.Link | T; - url(this: TokenizerThis, src: string, mangle: (cap: string) => string): Tokens.Link | T; - inlineText(this: TokenizerThis, src: string, smartypants: (cap: string) => string): Tokens.Text | T; + emStrong( + this: Tokenizer & TokenizerThis, + src: string, + maskedSrc: string, + prevChar: string, + ): Tokens.Em | Tokens.Strong | T; + codespan(this: Tokenizer & TokenizerThis, src: string): Tokens.Codespan | T; + br(this: Tokenizer & TokenizerThis, src: string): Tokens.Br | T; + del(this: Tokenizer & TokenizerThis, src: string): Tokens.Del | T; + autolink(this: Tokenizer & TokenizerThis, src: string, mangle: (cap: string) => string): Tokens.Link | T; + url(this: Tokenizer & TokenizerThis, src: string, mangle: (cap: string) => string): Tokens.Link | T; + inlineText(this: Tokenizer & TokenizerThis, src: string, smartypants: (cap: string) => string): Tokens.Text | T; } type TokenizerObject = Partial, 'constructor' | 'options'>>; @@ -161,39 +164,39 @@ export namespace marked { class Renderer { constructor(options?: MarkedOptions); options: MarkedOptions; - code(this: RendererThis, code: string, language: string | undefined, isEscaped: boolean): string | T; - blockquote(this: RendererThis, quote: string): string | T; - html(this: RendererThis, html: string): string | T; + code(this: Renderer | RendererThis, code: string, language: string | undefined, isEscaped: boolean): string | T; + blockquote(this: Renderer | RendererThis, quote: string): string | T; + html(this: Renderer | RendererThis, html: string): string | T; heading( - this: RendererThis, + this: Renderer | RendererThis, text: string, level: 1 | 2 | 3 | 4 | 5 | 6, raw: string, slugger: Slugger, ): string | T; - hr(this: RendererThis): string | T; - list(this: RendererThis, body: string, ordered: boolean, start: number): string | T; - listitem(this: RendererThis, text: string, task: boolean, checked: boolean): string | T; - checkbox(this: RendererThis, checked: boolean): string | T; - paragraph(this: RendererThis, text: string): string | T; - table(this: RendererThis, header: string, body: string): string | T; - tablerow(this: RendererThis, content: string): string | T; + hr(this: Renderer | RendererThis): string | T; + list(this: Renderer | RendererThis, body: string, ordered: boolean, start: number): string | T; + listitem(this: Renderer | RendererThis, text: string, task: boolean, checked: boolean): string | T; + checkbox(this: Renderer | RendererThis, checked: boolean): string | T; + paragraph(this: Renderer | RendererThis, text: string): string | T; + table(this: Renderer | RendererThis, header: string, body: string): string | T; + tablerow(this: Renderer | RendererThis, content: string): string | T; tablecell( - this: RendererThis, + this: Renderer | RendererThis, content: string, flags: { header: boolean; align: 'center' | 'left' | 'right' | null; }, ): string | T; - strong(this: RendererThis, text: string): string | T; - em(this: RendererThis, text: string): string | T; - codespan(this: RendererThis, code: string): string | T; - br(this: RendererThis): string | T; - del(this: RendererThis, text: string): string | T; - link(this: RendererThis, href: string | null, title: string | null, text: string): string | T; - image(this: RendererThis, href: string | null, title: string | null, text: string): string | T; - text(this: RendererThis, text: string): string | T; + strong(this: Renderer | RendererThis, text: string): string | T; + em(this: Renderer | RendererThis, text: string): string | T; + codespan(this: Renderer | RendererThis, code: string): string | T; + br(this: Renderer | RendererThis): string | T; + del(this: Renderer | RendererThis, text: string): string | T; + link(this: Renderer | RendererThis, href: string | null, title: string | null, text: string): string | T; + image(this: Renderer | RendererThis, href: string | null, title: string | null, text: string): string | T; + text(this: Renderer | RendererThis, text: string): string | T; } type RendererObject = Partial, 'constructor' | 'options'>>; @@ -221,7 +224,7 @@ export namespace marked { static parse(src: Token[] | TokensList, options?: MarkedOptions): string; static parseInline(src: Token[], options?: MarkedOptions): string; parse(src: Token[] | TokensList): string; - parseInline(src: Token[], renderer: Renderer): string; + parseInline(src: Token[], renderer?: Renderer): string; next(): Token; } @@ -236,8 +239,8 @@ export namespace marked { lex(src: string): TokensList; blockTokens(src: string, tokens: Token[]): Token[]; blockTokens(src: string, tokens: TokensList): TokensList; - inline(src: string, tokens: Token[]): void; - inlineTokens(src: string, tokens: Token[]): Token[]; + inline(src: string, tokens?: Token[]): Token[]; + inlineTokens(src: string, tokens?: Token[]): Token[]; state: { inLink: boolean; inRawBlock: boolean; @@ -461,7 +464,7 @@ export namespace marked { interface TokenizerExtension { name: string; level: 'block' | 'inline'; - start?: ((this: TokenizerThis, src: string) => number) | undefined; + start?: ((this: TokenizerThis, src: string) => number | void) | undefined; tokenizer: (this: TokenizerThis, src: string, tokens: Token[] | TokensList) => Tokens.Generic | void; childTokens?: string[] | undefined; } @@ -514,11 +517,7 @@ export namespace marked { * with an error if any occurred during highlighting and a string * if highlighting was successful) */ - highlight?( - code: string, - lang: string, - callback?: (error: any, code?: string) => void, - ): string | void; + highlight?(code: string, lang: string, callback?: (error: any, code?: string) => void): string | void; /** * Set the prefix for code block classes. diff --git a/src/vs/base/common/marked/marked.js b/src/vs/base/common/marked/marked.js index b7d8fe40e5e..052609801ac 100644 --- a/src/vs/base/common/marked/marked.js +++ b/src/vs/base/common/marked/marked.js @@ -83,6 +83,7 @@ function getDefaults() { return { + async: false, baseUrl: null, breaks: false, extensions: null, @@ -423,7 +424,7 @@ href: href, title: title, text: text, - tokens: lexer.inlineTokens(text, []) + tokens: lexer.inlineTokens(text) }; lexer.state.inLink = false; return token; @@ -531,15 +532,13 @@ } } - var token = { + return { type: 'heading', raw: cap[0], depth: cap[1].length, text: text, - tokens: [] + tokens: this.lexer.inline(text) }; - this.lexer.inline(token.text, token.tokens); - return token; } }; @@ -632,7 +631,9 @@ if (!endEarly) { var nextBulletRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}(?:[*+-]|\\d{1,9}[.)])((?: [^\\n]*)?(?:\\n|$))"); - var hrRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)"); // Check if following lines should be included in List Item + var hrRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)"); + var fencesBeginRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}(?:```|~~~)"); + var headingBeginRegex = new RegExp("^ {0," + Math.min(3, indent - 1) + "}#"); // Check if following lines should be included in List Item while (src) { rawLine = src.split('\n', 1)[0]; @@ -640,6 +641,16 @@ if (this.options.pedantic) { line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' '); + } // End list item if found code fences + + + if (fencesBeginRegex.test(line)) { + break; + } // End list item if found start of new heading + + + if (headingBeginRegex.test(line)) { + break; } // End list item if found start of new bullet @@ -757,10 +768,10 @@ }; if (this.options.sanitize) { + var text = this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0]); token.type = 'paragraph'; - token.text = this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0]); - token.tokens = []; - this.lexer.inline(token.text, token.tokens); + token.text = text; + token.tokens = this.lexer.inline(text); } return token; @@ -830,8 +841,7 @@ l = item.header.length; for (j = 0; j < l; j++) { - item.header[j].tokens = []; - this.lexer.inline(item.header[j].text, item.header[j].tokens); + item.header[j].tokens = this.lexer.inline(item.header[j].text); } // cell child tokens @@ -841,8 +851,7 @@ row = item.rows[j]; for (k = 0; k < row.length; k++) { - row[k].tokens = []; - this.lexer.inline(row[k].text, row[k].tokens); + row[k].tokens = this.lexer.inline(row[k].text); } } @@ -855,15 +864,13 @@ var cap = this.rules.block.lheading.exec(src); if (cap) { - var token = { + return { type: 'heading', raw: cap[0], depth: cap[2].charAt(0) === '=' ? 1 : 2, text: cap[1], - tokens: [] + tokens: this.lexer.inline(cap[1]) }; - this.lexer.inline(token.text, token.tokens); - return token; } }; @@ -871,14 +878,13 @@ var cap = this.rules.block.paragraph.exec(src); if (cap) { - var token = { + var text = cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]; + return { type: 'paragraph', raw: cap[0], - text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1], - tokens: [] + text: text, + tokens: this.lexer.inline(text) }; - this.lexer.inline(token.text, token.tokens); - return token; } }; @@ -886,14 +892,12 @@ var cap = this.rules.block.text.exec(src); if (cap) { - var token = { + return { type: 'text', raw: cap[0], text: cap[0], - tokens: [] + tokens: this.lexer.inline(cap[0]) }; - this.lexer.inline(token.text, token.tokens); - return token; } }; @@ -1072,7 +1076,7 @@ type: 'em', raw: src.slice(0, lLength + match.index + rLength + 1), text: _text, - tokens: this.lexer.inlineTokens(_text, []) + tokens: this.lexer.inlineTokens(_text) }; } // Create 'strong' if smallest delimiter has even char count. **a*** @@ -1082,7 +1086,7 @@ type: 'strong', raw: src.slice(0, lLength + match.index + rLength + 1), text: text, - tokens: this.lexer.inlineTokens(text, []) + tokens: this.lexer.inlineTokens(text) }; } } @@ -1128,7 +1132,7 @@ type: 'del', raw: cap[0], text: cap[2], - tokens: this.lexer.inlineTokens(cap[2], []) + tokens: this.lexer.inlineTokens(cap[2]) }; } }; @@ -1746,10 +1750,15 @@ }; _proto.inline = function inline(src, tokens) { + if (tokens === void 0) { + tokens = []; + } + this.inlineQueue.push({ src: src, tokens: tokens }); + return tokens; } /** * Lexing/Compiling @@ -2722,15 +2731,7 @@ return; } - try { - var _tokens = Lexer.lex(src, opt); - - if (opt.walkTokens) { - marked.walkTokens(_tokens, opt.walkTokens); - } - - return Parser.parse(_tokens, opt); - } catch (e) { + function onError(e) { e.message += '\nPlease report this to https://github.com/markedjs/marked.'; if (opt.silent) { @@ -2739,6 +2740,24 @@ throw e; } + + try { + var _tokens = Lexer.lex(src, opt); + + if (opt.walkTokens) { + if (opt.async) { + return Promise.all(marked.walkTokens(_tokens, opt.walkTokens)).then(function () { + return Parser.parse(_tokens, opt); + })["catch"](onError); + } + + marked.walkTokens(_tokens, opt.walkTokens); + } + + return Parser.parse(_tokens, opt); + } catch (e) { + onError(e); + } } /** * Options @@ -2903,11 +2922,14 @@ var _walkTokens = marked.defaults.walkTokens; opts.walkTokens = function (token) { - pack.walkTokens.call(this, token); + var values = []; + values.push(pack.walkTokens.call(this, token)); if (_walkTokens) { - _walkTokens.call(this, token); + values = values.concat(_walkTokens.call(this, token)); } + + return values; }; } @@ -2924,16 +2946,18 @@ marked.walkTokens = function (tokens, callback) { + var values = []; + var _loop3 = function _loop3() { var token = _step.value; - callback.call(marked, token); + values = values.concat(callback.call(marked, token)); switch (token.type) { case 'table': { for (var _iterator2 = _createForOfIteratorHelperLoose(token.header), _step2; !(_step2 = _iterator2()).done;) { var cell = _step2.value; - marked.walkTokens(cell.tokens, callback); + values = values.concat(marked.walkTokens(cell.tokens, callback)); } for (var _iterator3 = _createForOfIteratorHelperLoose(token.rows), _step3; !(_step3 = _iterator3()).done;) { @@ -2941,7 +2965,7 @@ for (var _iterator4 = _createForOfIteratorHelperLoose(row), _step4; !(_step4 = _iterator4()).done;) { var _cell = _step4.value; - marked.walkTokens(_cell.tokens, callback); + values = values.concat(marked.walkTokens(_cell.tokens, callback)); } } @@ -2950,7 +2974,7 @@ case 'list': { - marked.walkTokens(token.items, callback); + values = values.concat(marked.walkTokens(token.items, callback)); break; } @@ -2959,10 +2983,10 @@ if (marked.defaults.extensions && marked.defaults.extensions.childTokens && marked.defaults.extensions.childTokens[token.type]) { // Walk any extensions marked.defaults.extensions.childTokens[token.type].forEach(function (childTokens) { - marked.walkTokens(token[childTokens], callback); + values = values.concat(marked.walkTokens(token[childTokens], callback)); }); } else if (token.tokens) { - marked.walkTokens(token.tokens, callback); + values = values.concat(marked.walkTokens(token.tokens, callback)); } } } @@ -2971,6 +2995,8 @@ for (var _iterator = _createForOfIteratorHelperLoose(tokens), _step; !(_step = _iterator()).done;) { _loop3(); } + + return values; }; /** * Parse Inline diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 63d6a15b49e..243bb3b82d3 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -101,6 +101,11 @@ export namespace Schemas { * Scheme used vs live share */ export const vsls = 'vsls'; + + /** + * Scheme used for the Source Control commit input's text document + */ + export const vscodeSourceControl = 'vscode-scm'; } export const connectionTokenCookieName = 'vscode-tkn'; @@ -246,3 +251,53 @@ class FileAccessImpl { } export const FileAccess = new FileAccessImpl(); + + +export namespace COI { + + const coiHeaders = new Map<'3' | '2' | '1' | string, Record>([ + ['1', { 'Cross-Origin-Opener-Policy': 'same-origin' }], + ['2', { 'Cross-Origin-Embedder-Policy': 'require-corp' }], + ['3', { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' }], + ]); + + export const CoopAndCoep = Object.freeze(coiHeaders.get('3')); + + const coiSearchParamName = 'vscode-coi'; + + /** + * Extract desired headers from `vscode-coi` invocation + */ + export function getHeadersFromQuery(url: string | URI | URL): Record | undefined { + let params: URLSearchParams | undefined; + if (typeof url === 'string') { + params = new URL(url).searchParams; + } else if (url instanceof URL) { + params = url.searchParams; + } else if (URI.isUri(url)) { + params = new URL(url.toString(true)).searchParams; + } + const value = params?.get(coiSearchParamName); + if (!value) { + return undefined; + } + return coiHeaders.get(value); + } + + /** + * Add the `vscode-coi` query attribute based on wanting `COOP` and `COEP`. Will be a noop when `crossOriginIsolated` + * isn't enabled the current context + */ + export function addSearchParam(urlOrSearch: URLSearchParams | Record, coop: boolean, coep: boolean): void { + if (!(globalThis).crossOriginIsolated) { + // depends on the current context being COI + return; + } + const value = coop && coep ? '3' : coep ? '2' : '1'; + if (urlOrSearch instanceof URLSearchParams) { + urlOrSearch.set(coiSearchParamName, value); + } else { + (>urlOrSearch)[coiSearchParamName] = value; + } + } +} diff --git a/src/vs/base/common/objects.ts b/src/vs/base/common/objects.ts index 7c7c4483bd9..9e59345c09c 100644 --- a/src/vs/base/common/objects.ts +++ b/src/vs/base/common/objects.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { isArray, isTypedArray, isObject, isUndefinedOrNull } from 'vs/base/common/types'; +import { isTypedArray, isObject, isUndefinedOrNull } from 'vs/base/common/types'; export function deepClone(obj: T): T { if (!obj || typeof obj !== 'object') { @@ -61,7 +61,7 @@ function _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set): return changed; } - if (isArray(obj)) { + if (Array.isArray(obj)) { const r1: any[] = []; for (const e of obj) { r1.push(_cloneAndChange(e, changer, seen)); @@ -232,3 +232,38 @@ export function filter(obj: obj, predicate: (key: string, value: any) => boolean } return result; } + +export function getAllPropertyNames(obj: object): string[] { + let res: string[] = []; + let proto = Object.getPrototypeOf(obj); + while (Object.prototype !== proto) { + res = res.concat(Object.getOwnPropertyNames(proto)); + proto = Object.getPrototypeOf(proto); + } + return res; +} + +export function getAllMethodNames(obj: object): string[] { + const methods: string[] = []; + for (const prop of getAllPropertyNames(obj)) { + if (typeof (obj as any)[prop] === 'function') { + methods.push(prop); + } + } + return methods; +} + +export function createProxyObject(methodNames: string[], invoke: (method: string, args: unknown[]) => unknown): T { + const createProxyMethod = (method: string): () => unknown => { + return function () { + const args = Array.prototype.slice.call(arguments, 0); + return invoke(method, args); + }; + }; + + const result = {} as T; + for (const methodName of methodNames) { + (result)[methodName] = createProxyMethod(methodName); + } + return result; +} diff --git a/src/vs/base/common/observableImpl/base.ts b/src/vs/base/common/observableImpl/base.ts index fd91e6f8d8d..9d83083e49b 100644 --- a/src/vs/base/common/observableImpl/base.ts +++ b/src/vs/base/common/observableImpl/base.ts @@ -196,7 +196,7 @@ export class TransactionImpl implements ITransaction { export interface ISettableObservable extends IObservable, ISettable { } -export function observableValue(name: string, initialValue: T): ISettableObservable { +export function observableValue(name: string, initialValue: T): ISettableObservable { return new ObservableValue(name, initialValue); } diff --git a/src/vs/base/common/observableImpl/utils.ts b/src/vs/base/common/observableImpl/utils.ts index 0b07d089b83..2c11ff5eb5a 100644 --- a/src/vs/base/common/observableImpl/utils.ts +++ b/src/vs/base/common/observableImpl/utils.ts @@ -188,6 +188,42 @@ class FromEventObservableSignal extends BaseObservable { } } +export function observableSignal( + debugName: string +): IObservableSignal { + return new ObservableSignal(debugName); +} + +export interface IObservableSignal extends IObservable { + trigger(tx: ITransaction | undefined): void; +} + +class ObservableSignal extends BaseObservable implements IObservableSignal { + constructor( + public readonly debugName: string + ) { + super(); + } + + public trigger(tx: ITransaction | undefined): void { + if (!tx) { + transaction(tx => { + this.trigger(tx); + }, () => `Trigger signal ${this.debugName}`); + return; + } + + for (const o of this.observers) { + tx.updateObserver(o, this); + o.handleChange(this, undefined); + } + } + + public override get(): void { + // NO OP + } +} + export function debouncedObservable(observable: IObservable, debounceMs: number, disposableStore: DisposableStore): IObservable { const debouncedObservable = observableValue('debounced', undefined); diff --git a/src/vs/base/common/observableValue.ts b/src/vs/base/common/observableValue.ts index 7bdcbae66cb..e1f207c0841 100644 --- a/src/vs/base/common/observableValue.ts +++ b/src/vs/base/common/observableValue.ts @@ -5,17 +5,28 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +//@ts-ignore +import type { IObservable } from 'vs/base/common/observable'; +/** + * @deprecated Use {@link IObservable} instead. + */ export interface IObservableValue { onDidChange: Event; readonly value: T; } +/** + * @deprecated Use {@link IObservable} instead. + */ export const staticObservableValue = (value: T): IObservableValue => ({ onDidChange: Event.None, value, }); +/** + * @deprecated Use {@link IObservable} instead. + */ export class MutableObservableValue extends Disposable implements IObservableValue { private readonly changeEmitter = this._register(new Emitter()); diff --git a/src/vs/base/common/paging.ts b/src/vs/base/common/paging.ts index 60f72b407c3..1d9b7938169 100644 --- a/src/vs/base/common/paging.ts +++ b/src/vs/base/common/paging.ts @@ -6,7 +6,6 @@ import { range } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { canceled } from 'vs/base/common/errors'; -import { isArray } from 'vs/base/common/types'; /** * A Pager is a stateless abstraction over a paged collection. @@ -65,7 +64,7 @@ export class PagedModel implements IPagedModel { get length(): number { return this.pager.total; } constructor(arg: IPager | T[]) { - this.pager = isArray(arg) ? singlePagePager(arg) : arg; + this.pager = Array.isArray(arg) ? singlePagePager(arg) : arg; const totalPages = Math.ceil(this.pager.total / this.pager.pageSize); diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index 5dcf73fc4a3..1ae8079810e 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -99,9 +99,7 @@ export interface IProductConfiguration { readonly enableTelemetry?: boolean; readonly openToWelcomeMainPage?: boolean; readonly aiConfig?: { - readonly asimovKey: string; readonly ariaKey: string; - readonly preferAria: boolean; }; readonly sendASmile?: { @@ -155,7 +153,7 @@ export interface IProductConfiguration { readonly 'configurationSync.store'?: ConfigurationSyncStore; - readonly 'sessionSync.store'?: Omit; + readonly 'editSessions.store'?: Omit; readonly darwinUniversalAssetId?: string; } diff --git a/src/vs/base/common/sequence.ts b/src/vs/base/common/sequence.ts index ac3593d8990..2559c069be8 100644 --- a/src/vs/base/common/sequence.ts +++ b/src/vs/base/common/sequence.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; export interface ISplice { readonly start: number; @@ -33,26 +32,3 @@ export class Sequence implements ISequence, ISpliceable { this._onDidSplice.fire({ start, deleteCount, toInsert }); } } - -export class SimpleSequence implements ISequence { - - private _elements: T[]; - get elements(): T[] { return this._elements; } - - readonly onDidSplice: Event>; - private disposable: IDisposable; - - constructor(elements: T[], onDidAdd: Event, onDidRemove: Event) { - this._elements = [...elements]; - this.onDidSplice = Event.any( - Event.map(onDidAdd, e => ({ start: this.elements.length, deleteCount: 0, toInsert: [e] })), - Event.map(Event.filter(Event.map(onDidRemove, e => this.elements.indexOf(e)), i => i > -1), i => ({ start: i, deleteCount: 1, toInsert: [] })) - ); - - this.disposable = this.onDidSplice(({ start, deleteCount, toInsert }) => this._elements.splice(start, deleteCount, ...toInsert)); - } - - dispose(): void { - this.disposable.dispose(); - } -} diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 53796c58d8b..97bd9b3b055 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -600,15 +600,21 @@ export function getCharContainingOffset(str: string, offset: number): [number, n return [startOffset, endOffset]; } -/** - * Generated using https://github.com/alexdima/unicode-utils/blob/main/rtl-test.js - */ -const CONTAINS_RTL = /(?:[\u05BE\u05C0\u05C3\u05C6\u05D0-\u05F4\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F\u0671-\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u0710\u0712-\u072F\u074D-\u07A5\u07B1-\u07EA\u07F4\u07F5\u07FA\u07FE-\u0815\u081A\u0824\u0828\u0830-\u0858\u085E-\u088E\u08A0-\u08C9\u200F\uFB1D\uFB1F-\uFB28\uFB2A-\uFD3D\uFD50-\uFDC7\uFDF0-\uFDFC\uFE70-\uFEFC]|\uD802[\uDC00-\uDD1B\uDD20-\uDE00\uDE10-\uDE35\uDE40-\uDEE4\uDEEB-\uDF35\uDF40-\uDFFF]|\uD803[\uDC00-\uDD23\uDE80-\uDEA9\uDEAD-\uDF45\uDF51-\uDF81\uDF86-\uDFF6]|\uD83A[\uDC00-\uDCCF\uDD00-\uDD43\uDD4B-\uDFFF]|\uD83B[\uDC00-\uDEBB])/; +let CONTAINS_RTL: RegExp | undefined = undefined; + +function makeContainsRtl() { + // Generated using https://github.com/alexdima/unicode-utils/blob/main/rtl-test.js + return /(?:[\u05BE\u05C0\u05C3\u05C6\u05D0-\u05F4\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F\u0671-\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u0710\u0712-\u072F\u074D-\u07A5\u07B1-\u07EA\u07F4\u07F5\u07FA\u07FE-\u0815\u081A\u0824\u0828\u0830-\u0858\u085E-\u088E\u08A0-\u08C9\u200F\uFB1D\uFB1F-\uFB28\uFB2A-\uFD3D\uFD50-\uFDC7\uFDF0-\uFDFC\uFE70-\uFEFC]|\uD802[\uDC00-\uDD1B\uDD20-\uDE00\uDE10-\uDE35\uDE40-\uDEE4\uDEEB-\uDF35\uDF40-\uDFFF]|\uD803[\uDC00-\uDD23\uDE80-\uDEA9\uDEAD-\uDF45\uDF51-\uDF81\uDF86-\uDFF6]|\uD83A[\uDC00-\uDCCF\uDD00-\uDD43\uDD4B-\uDFFF]|\uD83B[\uDC00-\uDEBB])/; +} /** * Returns true if `str` contains any Unicode character that is classified as "R" or "AL". */ export function containsRTL(str: string): boolean { + if (!CONTAINS_RTL) { + CONTAINS_RTL = makeContainsRtl(); + } + return CONTAINS_RTL.test(str); } diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index 50ac38cf407..08063ae38d1 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -3,15 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI, UriComponents } from 'vs/base/common/uri'; - -/** - * @returns whether the provided parameter is a JavaScript Array or not. - */ -export function isArray(array: any): array is any[] { - return Array.isArray(array); -} - /** * @returns whether the provided parameter is a JavaScript String or not. */ @@ -27,7 +18,6 @@ export function isStringArray(value: unknown): value is string[] { } /** - * * @returns whether the provided parameter is of type `object` but **not** * `null`, an `array`, a `regexp`, nor a `date`. */ @@ -43,22 +33,12 @@ export function isObject(obj: unknown): obj is Object { } /** - * * @returns whether the provided parameter is of type `Buffer` or Uint8Array dervived type */ export function isTypedArray(obj: unknown): obj is Object { + const TypedArray = Object.getPrototypeOf(Uint8Array); return typeof obj === 'object' - && (obj instanceof Uint8Array || - obj instanceof Uint16Array || - obj instanceof Uint32Array || - obj instanceof Float32Array || - obj instanceof Float64Array || - obj instanceof Int8Array || - obj instanceof Int16Array || - obj instanceof Int32Array || - obj instanceof BigInt64Array || - obj instanceof BigUint64Array || - obj instanceof Uint8ClampedArray); + && obj instanceof TypedArray; } /** @@ -210,41 +190,6 @@ export function validateConstraint(arg: unknown, constraint: TypeConstraint | un } } -export function getAllPropertyNames(obj: object): string[] { - let res: string[] = []; - let proto = Object.getPrototypeOf(obj); - while (Object.prototype !== proto) { - res = res.concat(Object.getOwnPropertyNames(proto)); - proto = Object.getPrototypeOf(proto); - } - return res; -} - -export function getAllMethodNames(obj: object): string[] { - const methods: string[] = []; - for (const prop of getAllPropertyNames(obj)) { - if (typeof (obj as any)[prop] === 'function') { - methods.push(prop); - } - } - return methods; -} - -export function createProxyObject(methodNames: string[], invoke: (method: string, args: unknown[]) => unknown): T { - const createProxyMethod = (method: string): () => unknown => { - return function () { - const args = Array.prototype.slice.call(arguments, 0); - return invoke(method, args); - }; - }; - - const result = {} as T; - for (const methodName of methodNames) { - (result)[methodName] = createProxyMethod(methodName); - } - return result; -} - /** * Converts null to undefined, passes all other values through. */ @@ -275,12 +220,7 @@ export type AddFirstParameterToFunctions; */ -export type UriDto = { [K in keyof T]: T[K] extends URI - ? UriComponents - : UriDto }; - -export function assertNever(value: never, message = 'Unreachable'): never { - throw new Error(message); -} +export type AtLeastOne }> = Partial & U[keyof U]; diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 4aa3825cb4e..744afa00f0c 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -701,3 +701,10 @@ function percentDecode(str: string): string { } return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match)); } + +/** + * Mapped-type that replaces all occurrences of URI with UriComponents + */ +export type UriDto = { [K in keyof T]: T[K] extends URI + ? UriComponents + : UriDto }; diff --git a/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts index 5e9df9db7dd..17ecac8ff27 100644 --- a/src/vs/base/common/worker/simpleWorker.ts +++ b/src/vs/base/common/worker/simpleWorker.ts @@ -6,8 +6,8 @@ import { transformErrorForSerialization } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { getAllMethodNames } from 'vs/base/common/objects'; import { globals, isWeb } from 'vs/base/common/platform'; -import * as types from 'vs/base/common/types'; import * as strings from 'vs/base/common/strings'; const INITIALIZE = '$initialize'; @@ -332,7 +332,7 @@ export class SimpleWorkerClient extends Disp loaderConfiguration = globals.requirejs.s.contexts._.config; } - const hostMethods = types.getAllMethodNames(host); + const hostMethods = getAllMethodNames(host); // Send initialize message this._onModuleLoaded = this._protocol.sendMessage(INITIALIZE, [ @@ -507,7 +507,7 @@ export class SimpleWorkerServer { if (this._requestHandlerFactory) { // static request handler this._requestHandler = this._requestHandlerFactory(hostProxy); - return Promise.resolve(types.getAllMethodNames(this._requestHandler)); + return Promise.resolve(getAllMethodNames(this._requestHandler)); } if (loaderConfig) { @@ -548,7 +548,7 @@ export class SimpleWorkerServer { return; } - resolve(types.getAllMethodNames(this._requestHandler)); + resolve(getAllMethodNames(this._requestHandler)); }, reject); }); } diff --git a/src/vs/base/node/decoder.ts b/src/vs/base/node/decoder.ts deleted file mode 100644 index 36a3de5175c..00000000000 --- a/src/vs/base/node/decoder.ts +++ /dev/null @@ -1,62 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as sd from 'string_decoder'; -import { CharCode } from 'vs/base/common/charCode'; - -/** - * Convenient way to iterate over output line by line. This helper accommodates for the fact that - * a buffer might not end with new lines all the way. - * - * To use: - * - call the write method - * - forEach() over the result to get the lines - */ -export class LineDecoder { - private stringDecoder: sd.StringDecoder; - private remaining: string | null; - - constructor(encoding: BufferEncoding = 'utf8') { - this.stringDecoder = new sd.StringDecoder(encoding); - this.remaining = null; - } - - write(buffer: Buffer): string[] { - const result: string[] = []; - const value = this.remaining - ? this.remaining + this.stringDecoder.write(buffer) - : this.stringDecoder.write(buffer); - - if (value.length < 1) { - return result; - } - let start = 0; - let ch: number; - let idx = start; - while (idx < value.length) { - ch = value.charCodeAt(idx); - if (ch === CharCode.CarriageReturn || ch === CharCode.LineFeed) { - result.push(value.substring(start, idx)); - idx++; - if (idx < value.length) { - const lastChar = ch; - ch = value.charCodeAt(idx); - if ((lastChar === CharCode.CarriageReturn && ch === CharCode.LineFeed) || (lastChar === CharCode.LineFeed && ch === CharCode.CarriageReturn)) { - idx++; - } - } - start = idx; - } else { - idx++; - } - } - this.remaining = start < value.length ? value.substr(start) : null; - return result; - } - - end(): string | null { - return this.remaining; - } -} diff --git a/src/vs/base/node/languagePacks.d.ts b/src/vs/base/node/languagePacks.d.ts index 5c69043ef23..87bff5b75a4 100644 --- a/src/vs/base/node/languagePacks.d.ts +++ b/src/vs/base/node/languagePacks.d.ts @@ -21,4 +21,4 @@ export interface InternalNLSConfiguration extends NLSConfiguration { _languagePackSupport?: boolean; } -export function getNLSConfiguration(commit: string, userDataPath: string, metaDataFile: string, locale: string): Promise; +export function getNLSConfiguration(commit: string | undefined, userDataPath: string, metaDataFile: string, locale: string): Promise; diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js index f99d3808de5..9a554301a27 100644 --- a/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js @@ -68,12 +68,12 @@ /** * @param {string} userDataPath - * @returns {object} + * @returns {Promise} */ - function getLanguagePackConfigurations(userDataPath) { + async function getLanguagePackConfigurations(userDataPath) { const configFile = path.join(userDataPath, 'languagepacks.json'); try { - return nodeRequire(configFile); + return JSON.parse(await readFile(configFile)); } catch (err) { // Do nothing. If we can't read the file we have no // language pack config. @@ -83,7 +83,7 @@ /** * @param {object} config - * @param {string} locale + * @param {string | undefined} locale */ function resolveLanguagePackLocale(config, locale) { try { @@ -106,10 +106,10 @@ } /** - * @param {string} commit + * @param {string | undefined} commit * @param {string} userDataPath * @param {string} metaDataFile - * @param {string} locale + * @param {string | undefined} locale */ function getNLSConfiguration(commit, userDataPath, metaDataFile, locale) { if (locale === 'pseudo') { @@ -141,94 +141,95 @@ if (!commit) { return defaultResult(initialLocale); } - const configs = getLanguagePackConfigurations(userDataPath); - if (!configs) { - return defaultResult(initialLocale); - } - locale = resolveLanguagePackLocale(configs, locale); - if (!locale) { - return defaultResult(initialLocale); - } - const packConfig = configs[locale]; - let mainPack; - if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') { - return defaultResult(initialLocale); - } - return exists(mainPack).then(fileExists => { - if (!fileExists) { + return getLanguagePackConfigurations(userDataPath).then(configs => { + if (!configs) { return defaultResult(initialLocale); } - const packId = packConfig.hash + '.' + locale; - const cacheRoot = path.join(userDataPath, 'clp', packId); - const coreLocation = path.join(cacheRoot, commit); - const translationsConfigFile = path.join(cacheRoot, 'tcf.json'); - const corruptedFile = path.join(cacheRoot, 'corrupted.info'); - const result = { - locale: initialLocale, - availableLanguages: { '*': locale }, - _languagePackId: packId, - _translationsConfigFile: translationsConfigFile, - _cacheRoot: cacheRoot, - _resolvedLanguagePackCoreLocation: coreLocation, - _corruptedFile: corruptedFile - }; - return exists(corruptedFile).then(corrupted => { - // The nls cache directory is corrupted. - let toDelete; - if (corrupted) { - toDelete = rimraf(cacheRoot); - } else { - toDelete = Promise.resolve(undefined); + locale = resolveLanguagePackLocale(configs, locale); + if (!locale) { + return defaultResult(initialLocale); + } + const packConfig = configs[locale]; + let mainPack; + if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') { + return defaultResult(initialLocale); + } + return exists(mainPack).then(fileExists => { + if (!fileExists) { + return defaultResult(initialLocale); } - return toDelete.then(() => { - return exists(coreLocation).then(fileExists => { - if (fileExists) { - // We don't wait for this. No big harm if we can't touch - touch(coreLocation).catch(() => { }); - perf.mark('code/didGenerateNls'); - return result; - } - return mkdirp(coreLocation).then(() => { - return Promise.all([readFile(metaDataFile), readFile(mainPack)]); - }).then(values => { - const metadata = JSON.parse(values[0]); - const packData = JSON.parse(values[1]).contents; - const bundles = Object.keys(metadata.bundles); - const writes = []; - for (const bundle of bundles) { - const modules = metadata.bundles[bundle]; - const target = Object.create(null); - for (const module of modules) { - const keys = metadata.keys[module]; - const defaultMessages = metadata.messages[module]; - const translations = packData[module]; - let targetStrings; - if (translations) { - targetStrings = []; - for (let i = 0; i < keys.length; i++) { - const elem = keys[i]; - const key = typeof elem === 'string' ? elem : elem.key; - let translatedMessage = translations[key]; - if (translatedMessage === undefined) { - translatedMessage = defaultMessages[i]; - } - targetStrings.push(translatedMessage); - } - } else { - targetStrings = defaultMessages; - } - target[module] = targetStrings; - } - writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); + const packId = packConfig.hash + '.' + locale; + const cacheRoot = path.join(userDataPath, 'clp', packId); + const coreLocation = path.join(cacheRoot, commit); + const translationsConfigFile = path.join(cacheRoot, 'tcf.json'); + const corruptedFile = path.join(cacheRoot, 'corrupted.info'); + const result = { + locale: initialLocale, + availableLanguages: { '*': locale }, + _languagePackId: packId, + _translationsConfigFile: translationsConfigFile, + _cacheRoot: cacheRoot, + _resolvedLanguagePackCoreLocation: coreLocation, + _corruptedFile: corruptedFile + }; + return exists(corruptedFile).then(corrupted => { + // The nls cache directory is corrupted. + let toDelete; + if (corrupted) { + toDelete = rimraf(cacheRoot); + } else { + toDelete = Promise.resolve(undefined); + } + return toDelete.then(() => { + return exists(coreLocation).then(fileExists => { + if (fileExists) { + // We don't wait for this. No big harm if we can't touch + touch(coreLocation).catch(() => { }); + perf.mark('code/didGenerateNls'); + return result; } - writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); - return Promise.all(writes); - }).then(() => { - perf.mark('code/didGenerateNls'); - return result; - }).catch(err => { - console.error('Generating translation files failed.', err); - return defaultResult(locale); + return mkdirp(coreLocation).then(() => { + return Promise.all([readFile(metaDataFile), readFile(mainPack)]); + }).then(values => { + const metadata = JSON.parse(values[0]); + const packData = JSON.parse(values[1]).contents; + const bundles = Object.keys(metadata.bundles); + const writes = []; + for (const bundle of bundles) { + const modules = metadata.bundles[bundle]; + const target = Object.create(null); + for (const module of modules) { + const keys = metadata.keys[module]; + const defaultMessages = metadata.messages[module]; + const translations = packData[module]; + let targetStrings; + if (translations) { + targetStrings = []; + for (let i = 0; i < keys.length; i++) { + const elem = keys[i]; + const key = typeof elem === 'string' ? elem : elem.key; + let translatedMessage = translations[key]; + if (translatedMessage === undefined) { + translatedMessage = defaultMessages[i]; + } + targetStrings.push(translatedMessage); + } + } else { + targetStrings = defaultMessages; + } + target[module] = targetStrings; + } + writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); + } + writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); + return Promise.all(writes); + }).then(() => { + perf.mark('code/didGenerateNls'); + return result; + }).catch(err => { + console.error('Generating translation files failed.', err); + return defaultResult(locale); + }); }); }); }); diff --git a/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts index 2283c4a61d6..28e6ca7e887 100644 --- a/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -66,7 +66,11 @@ async function rimrafMove(path: string): Promise { // https://github.com/microsoft/vscode/issues/139908 await fs.promises.rename(path, pathInTemp); } catch (error) { - return rimrafUnlink(path); // if rename fails, delete without tmp dir + if (error.code === 'ENOENT') { + return; // ignore - path to delete did not exist + } + + return rimrafUnlink(path); // otherwise fallback to unlink } // Delete but do not return as promise @@ -390,6 +394,9 @@ interface IEnsuredWriteFileOptions extends IWriteFileOptions { } let canFlush = true; +export function configureFlushOnWrite(enabled: boolean): void { + canFlush = enabled; +} // Calls fs.writeFile() followed by a fs.sync() call to flush the changes to disk // We do this in cases where we want to make sure the data is really on disk and @@ -421,7 +428,7 @@ function doWriteFileAndFlush(path: string, data: string | Buffer | Uint8Array, o // In that case we disable flushing and warn to the console if (syncError) { console.warn('[node.js fs] fdatasync is now disabled for this session because it failed: ', syncError); - canFlush = false; + configureFlushOnWrite(false); } return fs.close(fd, closeError => callback(closeError)); @@ -455,7 +462,7 @@ export function writeFileSync(path: string, data: string | Buffer, options?: IWr fs.fdatasyncSync(fd); // https://github.com/microsoft/vscode/issues/9589 } catch (syncError) { console.warn('[node.js fs] fdatasyncSync is now disabled for this session because it failed: ', syncError); - canFlush = false; + configureFlushOnWrite(false); } } finally { fs.closeSync(fd); diff --git a/src/vs/base/node/processes.ts b/src/vs/base/node/processes.ts index 1a27f7543c3..a71a7b8cb4e 100644 --- a/src/vs/base/node/processes.ts +++ b/src/vs/base/node/processes.ts @@ -5,392 +5,23 @@ import * as cp from 'child_process'; import { Stats } from 'fs'; -import { IStringDictionary } from 'vs/base/common/collections'; -import * as extpath from 'vs/base/common/extpath'; -import { FileAccess } from 'vs/base/common/network'; -import * as Objects from 'vs/base/common/objects'; import * as path from 'vs/base/common/path'; import * as Platform from 'vs/base/common/platform'; import * as process from 'vs/base/common/process'; -import { CommandOptions, Executable, ForkOptions, Source, SuccessData, TerminateResponse, TerminateResponseCode } from 'vs/base/common/processes'; +import { CommandOptions, ForkOptions, Source, SuccessData, TerminateResponse, TerminateResponseCode } from 'vs/base/common/processes'; import * as Types from 'vs/base/common/types'; -import { LineDecoder } from 'vs/base/node/decoder'; import * as pfs from 'vs/base/node/pfs'; -import * as nls from 'vs/nls'; export { CommandOptions, ForkOptions, SuccessData, Source, TerminateResponse, TerminateResponseCode }; export type ValueCallback = (value: T | Promise) => void; export type ErrorCallback = (error?: any) => void; export type ProgressCallback = (progress: T) => void; -export interface LineData { - line: string; - source: Source; -} - -function getWindowsCode(status: number): TerminateResponseCode { - switch (status) { - case 0: - return TerminateResponseCode.Success; - case 1: - return TerminateResponseCode.AccessDenied; - case 128: - return TerminateResponseCode.ProcessNotFound; - default: - return TerminateResponseCode.Unknown; - } -} - -function terminateProcess(process: cp.ChildProcess, cwd?: string): Promise { - if (Platform.isWindows) { - try { - const options: any = { - stdio: ['pipe', 'pipe', 'ignore'] - }; - if (cwd) { - options.cwd = cwd; - } - const killProcess = cp.execFile('taskkill', ['/T', '/F', '/PID', process.pid!.toString()], options); - return new Promise(resolve => { - 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 Promise.resolve({ success: false, error: err, code: err.status ? getWindowsCode(err.status) : TerminateResponseCode.Unknown }); - } - } else if (Platform.isLinux || Platform.isMacintosh) { - try { - const cmd = FileAccess.asFileUri('vs/base/node/terminateProcess.sh', require).fsPath; - return new Promise(resolve => { - 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 Promise.resolve({ success: false, error: err }); - } - } else { - process.kill('SIGKILL'); - } - return Promise.resolve({ success: true }); -} export function getWindowsShell(env = process.env as Platform.IProcessEnvironment): string { return env['comspec'] || 'cmd.exe'; } -export abstract class AbstractProcess { - private cmd: string; - private args: string[]; - private options: CommandOptions | ForkOptions; - protected shell: boolean; - - private childProcess: cp.ChildProcess | null; - protected childProcessPromise: Promise | null; - private pidResolve: ValueCallback | undefined; - protected terminateRequested: boolean; - - private static WellKnowCommands: IStringDictionary = { - 'ant': true, - 'cmake': true, - 'eslint': true, - 'gradle': true, - 'grunt': true, - 'gulp': true, - 'jake': true, - 'jenkins': true, - 'jshint': true, - 'make': true, - 'maven': true, - 'msbuild': true, - 'msc': true, - 'nmake': true, - 'npm': true, - 'rake': true, - 'tsc': true, - 'xbuild': true - }; - - public constructor(executable: Executable); - public constructor(cmd: string, args: string[] | undefined, shell: boolean, options: CommandOptions | undefined); - public constructor(arg1: string | Executable, arg2?: string[], arg3?: boolean, arg4?: CommandOptions) { - if (arg2 !== undefined && arg3 !== undefined && arg4 !== undefined) { - this.cmd = arg1; - this.args = arg2; - this.shell = arg3; - this.options = arg4; - } else { - const executable = arg1; - this.cmd = executable.command; - this.shell = executable.isShellCommand; - this.args = executable.args.slice(0); - this.options = executable.options || {}; - } - - this.childProcess = null; - this.childProcessPromise = null; - this.terminateRequested = false; - - if (this.options.env) { - const newEnv: IStringDictionary = Object.create(null); - Object.keys(process.env).forEach((key) => { - newEnv[key] = process.env[key]!; - }); - Object.keys(this.options.env).forEach((key) => { - newEnv[key] = this.options.env![key]!; - }); - this.options.env = newEnv; - } - } - - public getSanitizedCommand(): string { - let result = this.cmd.toLowerCase(); - const index = result.lastIndexOf(path.sep); - if (index !== -1) { - result = result.substring(index + 1); - } - if (AbstractProcess.WellKnowCommands[result]) { - return result; - } - return 'other'; - } - - public start(pp: ProgressCallback): Promise { - if (Platform.isWindows && ((this.options && this.options.cwd && extpath.isUNC(this.options.cwd)) || !this.options && extpath.isUNC(process.cwd()))) { - return Promise.reject(new Error(nls.localize('TaskRunner.UNC', 'Can\'t execute a shell command on a UNC drive.'))); - } - return this.useExec().then((useExec) => { - let cc: ValueCallback; - let ee: ErrorCallback; - const result = new Promise((c, e) => { - cc = c; - ee = e; - }); - - if (useExec) { - let cmd: string = this.cmd; - if (this.args) { - cmd = cmd + ' ' + this.args.join(' '); - } - this.childProcess = cp.exec(cmd, this.options, (error, stdout, stderr) => { - this.childProcess = null; - const err: any = error; - // This is tricky since executing a command shell reports error back in case the executed command return an - // error or the command didn't exist at all. So we can't blindly treat an error as a failed command. So we - // always parse the output and report success unless the job got killed. - if (err && err.killed) { - ee({ killed: this.terminateRequested, stdout: stdout.toString(), stderr: stderr.toString() }); - } else { - this.handleExec(cc, pp, error, stdout as any, stderr as any); - } - }); - } else { - let childProcess: cp.ChildProcess | null = null; - const closeHandler = (data: any) => { - this.childProcess = null; - this.childProcessPromise = null; - this.handleClose(data, cc, pp, ee); - const result: SuccessData = { - terminated: this.terminateRequested - }; - if (Types.isNumber(data)) { - result.cmdCode = data; - } - cc(result); - }; - if (this.shell && Platform.isWindows) { - const options: any = Objects.deepClone(this.options); - options.windowsVerbatimArguments = true; - options.detached = false; - let quotedCommand: boolean = false; - let quotedArg: boolean = false; - const commandLine: string[] = []; - let quoted = this.ensureQuotes(this.cmd); - commandLine.push(quoted.value); - quotedCommand = quoted.quoted; - if (this.args) { - this.args.forEach((elem) => { - quoted = this.ensureQuotes(elem); - commandLine.push(quoted.value); - quotedArg = quotedArg && quoted.quoted; - }); - } - const args: string[] = [ - '/s', - '/c', - ]; - if (quotedCommand) { - if (quotedArg) { - args.push('"' + commandLine.join(' ') + '"'); - } else if (commandLine.length > 1) { - args.push('"' + commandLine[0] + '"' + ' ' + commandLine.slice(1).join(' ')); - } else { - args.push('"' + commandLine[0] + '"'); - } - } else { - args.push(commandLine.join(' ')); - } - childProcess = cp.spawn(getWindowsShell(), args, options); - } else { - if (this.cmd) { - childProcess = cp.spawn(this.cmd, this.args, this.options); - } - } - if (childProcess) { - this.childProcess = childProcess; - this.childProcessPromise = Promise.resolve(childProcess); - if (this.pidResolve) { - this.pidResolve(Types.isNumber(childProcess.pid) ? childProcess.pid : -1); - this.pidResolve = undefined; - } - childProcess.on('error', (error: Error) => { - this.childProcess = null; - ee({ terminated: this.terminateRequested, error: error }); - }); - if (childProcess.pid) { - this.childProcess.on('close', closeHandler); - this.handleSpawn(childProcess, cc!, pp, ee!, true); - } - } - } - return result; - }); - } - - protected abstract handleExec(cc: ValueCallback, pp: ProgressCallback, error: Error | null, stdout: Buffer, stderr: Buffer): void; - protected abstract handleSpawn(childProcess: cp.ChildProcess, cc: ValueCallback, pp: ProgressCallback, ee: ErrorCallback, sync: boolean): void; - - protected handleClose(data: any, cc: ValueCallback, pp: ProgressCallback, ee: ErrorCallback): void { - // Default is to do nothing. - } - - private static readonly regexp = /^[^"].* .*[^"]/; - private ensureQuotes(value: string) { - if (AbstractProcess.regexp.test(value)) { - return { - value: '"' + value + '"', //`"${value}"`, - quoted: true - }; - } else { - return { - value: value, - quoted: value.length > 0 && value[0] === '"' && value[value.length - 1] === '"' - }; - } - } - - public get pid(): Promise { - if (this.childProcessPromise) { - return this.childProcessPromise.then(childProcess => childProcess.pid!, err => -1); - } else { - return new Promise((resolve) => { - this.pidResolve = resolve; - }); - } - } - - public terminate(): Promise { - if (!this.childProcessPromise) { - return Promise.resolve({ success: true }); - } - return this.childProcessPromise.then((childProcess) => { - this.terminateRequested = true; - return terminateProcess(childProcess, this.options.cwd).then(response => { - if (response.success) { - this.childProcess = null; - } - return response; - }); - }, (err) => { - return { success: true }; - }); - } - - private useExec(): Promise { - return new Promise(resolve => { - if (!this.shell || !Platform.isWindows) { - return resolve(false); - } - const cmdShell = cp.spawn(getWindowsShell(), ['/s', '/c']); - cmdShell.on('error', (error: Error) => { - return resolve(true); - }); - cmdShell.on('exit', (data: any) => { - return resolve(false); - }); - }); - } -} - -export class LineProcess extends AbstractProcess { - - 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) { - [stdout, stderr].forEach((buffer: Buffer, index: number) => { - const lineDecoder = new LineDecoder(); - const lines = lineDecoder.write(buffer); - lines.forEach((line) => { - pp({ line: line, source: index === 0 ? Source.stdout : Source.stderr }); - }); - const line = lineDecoder.end(); - if (line) { - pp({ line: line, source: index === 0 ? Source.stdout : Source.stderr }); - } - }); - cc({ terminated: this.terminateRequested, error: error }); - } - - protected handleSpawn(childProcess: cp.ChildProcess, cc: ValueCallback, pp: ProgressCallback, ee: ErrorCallback, sync: boolean): void { - 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 = stderrLineDecoder.write(data); - lines.forEach(line => pp({ line: line, source: Source.stderr })); - }); - - this.stdoutLineDecoder = stdoutLineDecoder; - this.stderrLineDecoder = stderrLineDecoder; - } - - protected override handleClose(data: any, cc: ValueCallback, pp: ProgressCallback, ee: ErrorCallback): void { - 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 }); - } - } -} - export interface IQueuedSender { send: (msg: any) => void; } diff --git a/src/vs/base/node/ps.ts b/src/vs/base/node/ps.ts index 8fd62606254..8498145bed2 100644 --- a/src/vs/base/node/ps.ts +++ b/src/vs/base/node/ps.ts @@ -52,7 +52,7 @@ export function listProcesses(rootPid: number): Promise { const ISSUE_REPORTER_HINT = /--vscode-window-kind=issue-reporter/; const PROCESS_EXPLORER_HINT = /--vscode-window-kind=process-explorer/; const UTILITY_NETWORK_HINT = /--utility-sub-type=network/; - const UTILITY_EXTENSION_HOST_HINT = /--vscode-utility-kind=extensionHost/; + const UTILITY_EXTENSION_HOST_HINT = /--utility-sub-type=node.mojom.NodeService/; const WINDOWS_CRASH_REPORTER = /--crashes-directory/; const WINDOWS_PTY = /\\pipe\\winpty-control/; const WINDOWS_CONSOLE_HOST = /conhost\.exe/; diff --git a/src/vs/base/node/zip.ts b/src/vs/base/node/zip.ts index c815e61861a..2033f7cd98e 100644 --- a/src/vs/base/node/zip.ts +++ b/src/vs/base/node/zip.ts @@ -81,9 +81,7 @@ function extractEntry(stream: Readable, fileName: string, mode: number, targetPa let istream: WriteStream; token.onCancellationRequested(() => { - if (istream) { - istream.destroy(); - } + istream?.destroy(); }); return Promise.resolve(Promises.mkdir(targetDirName, { recursive: true })).then(() => new Promise((c, e) => { diff --git a/src/vs/base/parts/ipc/common/ipc.net.ts b/src/vs/base/parts/ipc/common/ipc.net.ts index 5d464d87e87..fc0a55f8d48 100644 --- a/src/vs/base/parts/ipc/common/ipc.net.ts +++ b/src/vs/base/parts/ipc/common/ipc.net.ts @@ -136,6 +136,12 @@ export interface WebSocketCloseEvent { export type SocketCloseEvent = NodeSocketCloseEvent | WebSocketCloseEvent | undefined; +export interface SocketTimeoutEvent { + readonly unacknowledgedMsgCount: number; + readonly timeSinceOldestUnacknowledgedMsg: number; + readonly timeSinceLastReceivedSomeData: number; +} + export interface ISocket extends IDisposable { onData(listener: (e: VSBuffer) => void): IDisposable; onClose(listener: (e: SocketCloseEvent) => void): IDisposable; @@ -256,7 +262,8 @@ const enum ProtocolMessageType { Disconnect = 5, ReplayRequest = 6, Pause = 7, - Resume = 8 + Resume = 8, + KeepAlive = 9, } function protocolMessageTypeToString(messageType: ProtocolMessageType) { @@ -269,6 +276,7 @@ function protocolMessageTypeToString(messageType: ProtocolMessageType) { case ProtocolMessageType.ReplayRequest: return 'ReplayRequest'; case ProtocolMessageType.Pause: return 'PauseWriting'; case ProtocolMessageType.Resume: return 'ResumeWriting'; + case ProtocolMessageType.KeepAlive: return 'KeepAlive'; } } @@ -667,6 +675,16 @@ class Queue { this._last = null; } + public length(): number { + let result = 0; + let current = this._first; + while (current) { + current = current.next; + result++; + } + return result; + } + public peek(): T | null { if (!this._first) { return null; @@ -778,6 +796,8 @@ export class PersistentProtocol implements IMessagePassingProtocol { private _incomingMsgLastTime: number; private _incomingAckTimeout: any | null; + private _keepAliveInterval: any | null; + private _lastReplayRequestTime: number; private _lastSocketTimeoutTime: number; @@ -800,8 +820,8 @@ export class PersistentProtocol implements IMessagePassingProtocol { private readonly _onSocketClose = new BufferedEmitter(); readonly onSocketClose: Event = this._onSocketClose.event; - private readonly _onSocketTimeout = new BufferedEmitter(); - readonly onSocketTimeout: Event = this._onSocketTimeout.event; + private readonly _onSocketTimeout = new BufferedEmitter(); + readonly onSocketTimeout: Event = this._onSocketTimeout.event; public get unacknowledgedCount(): number { return this._outgoingMsgId - this._outgoingAckId; @@ -834,6 +854,11 @@ export class PersistentProtocol implements IMessagePassingProtocol { if (initialChunk) { this._socketReader.acceptChunk(initialChunk); } + + // send a message every 5s + this._keepAliveInterval = setInterval(() => { + this._sendKeepAlive(); + }, 5000); } dispose(): void { @@ -845,6 +870,10 @@ export class PersistentProtocol implements IMessagePassingProtocol { clearTimeout(this._incomingAckTimeout); this._incomingAckTimeout = null; } + if (this._keepAliveInterval) { + clearInterval(this._keepAliveInterval); + this._keepAliveInterval = null; + } this._socketDisposables = dispose(this._socketDisposables); } @@ -966,7 +995,7 @@ export class PersistentProtocol implements IMessagePassingProtocol { break; } case ProtocolMessageType.Ack: { - // nothing to do + // nothing to do, .ack is handled above already break; } case ProtocolMessageType.Disconnect: { @@ -990,6 +1019,10 @@ export class PersistentProtocol implements IMessagePassingProtocol { this._socketWriter.resume(); break; } + case ProtocolMessageType.KeepAlive: { + // nothing to do + break; + } } } @@ -1081,7 +1114,11 @@ export class PersistentProtocol implements IMessagePassingProtocol { if (!this._loadEstimator.hasHighLoad()) { // Trash the socket this._lastSocketTimeoutTime = Date.now(); - this._onSocketTimeout.fire(undefined); + this._onSocketTimeout.fire({ + unacknowledgedMsgCount: this._outgoingUnackMsg.length(), + timeSinceOldestUnacknowledgedMsg, + timeSinceLastReceivedSomeData + }); return; } } @@ -1109,6 +1146,11 @@ export class PersistentProtocol implements IMessagePassingProtocol { const msg = new ProtocolMessage(ProtocolMessageType.Ack, 0, this._incomingAckId, getEmptyBuffer()); this._socketWriter.write(msg); } + + private _sendKeepAlive(): void { + const msg = new ProtocolMessage(ProtocolMessageType.KeepAlive, 0, 0, getEmptyBuffer()); + this._socketWriter.write(msg); + } } // (() => { diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 93f944934f3..3979b73f208 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -8,7 +8,7 @@ import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/com import { VSBuffer } from 'vs/base/common/buffer'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { memoize } from 'vs/base/common/decorators'; -import * as errors from 'vs/base/common/errors'; +import { CancellationError } from 'vs/base/common/errors'; import { Emitter, Event, EventMultiplexer, Relay } from 'vs/base/common/event'; import { combinedDisposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; @@ -516,7 +516,7 @@ export class ChannelClient implements IChannelClient, IDisposable { return { call(command: string, arg?: any, cancellationToken?: CancellationToken) { if (that.isDisposed) { - return Promise.reject(errors.canceled()); + return Promise.reject(new CancellationError()); } return that.requestPromise(channelName, command, arg, cancellationToken); }, @@ -535,14 +535,14 @@ export class ChannelClient implements IChannelClient, IDisposable { const request: IRawRequest = { id, type, channelName, name, arg }; if (cancellationToken.isCancellationRequested) { - return Promise.reject(errors.canceled()); + return Promise.reject(new CancellationError()); } let disposable: IDisposable; const result = new Promise((c, e) => { if (cancellationToken.isCancellationRequested) { - return e(errors.canceled()); + return e(new CancellationError()); } const doRequest = () => { @@ -591,7 +591,7 @@ export class ChannelClient implements IChannelClient, IDisposable { this.sendRequest({ id, type: RequestType.PromiseCancel }); } - e(errors.canceled()); + e(new CancellationError()); }; const cancellationTokenListener = cancellationToken.onCancellationRequested(cancel); diff --git a/src/vs/base/parts/ipc/electron-main/ipc.electron.ts b/src/vs/base/parts/ipc/electron-main/ipc.electron.ts index f0d395c4bfa..b40d381cffb 100644 --- a/src/vs/base/parts/ipc/electron-main/ipc.electron.ts +++ b/src/vs/base/parts/ipc/electron-main/ipc.electron.ts @@ -37,9 +37,7 @@ export class Server extends IPCServer { const id = webContents.id; const client = Server.Clients.get(id); - if (client) { - client.dispose(); - } + client?.dispose(); const onDidClientReconnect = new Emitter(); Server.Clients.set(id, toDisposable(() => onDidClientReconnect.fire())); diff --git a/src/vs/base/parts/ipc/node/ipc.cp.ts b/src/vs/base/parts/ipc/node/ipc.cp.ts index fa6d8073ab7..90595976349 100644 --- a/src/vs/base/parts/ipc/node/ipc.cp.ts +++ b/src/vs/base/parts/ipc/node/ipc.cp.ts @@ -241,9 +241,7 @@ export class Client implements IChannelClient, IDisposable { console.warn('IPC "' + this.options.serverName + '" crashed with exit code ' + code + ' and signal ' + signal); } - if (this.disposeDelayer) { - this.disposeDelayer.cancel(); - } + this.disposeDelayer?.cancel(); this.disposeClient(); this._onDidProcessExit.fire({ code, signal }); }); diff --git a/src/vs/base/parts/ipc/node/ipc.net.ts b/src/vs/base/parts/ipc/node/ipc.net.ts index 9831dcde97c..bff8e41d8e5 100644 --- a/src/vs/base/parts/ipc/node/ipc.net.ts +++ b/src/vs/base/parts/ipc/node/ipc.net.ts @@ -3,9 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createHash } from 'crypto'; -import { createConnection, createServer, Server as NetServer, Socket } from 'net'; -import { tmpdir } from 'os'; +// import { createHash } from 'crypto'; +import type { Server as NetServer, Socket } from 'net'; +// import { tmpdir } from 'os'; +import type * as zlib from 'zlib'; import { VSBuffer } from 'vs/base/common/buffer'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; @@ -15,7 +16,16 @@ import { Platform, platform } from 'vs/base/common/platform'; import { generateUuid } from 'vs/base/common/uuid'; import { ClientConnectionEvent, IPCServer } from 'vs/base/parts/ipc/common/ipc'; import { ChunkStream, Client, ISocket, Protocol, SocketCloseEvent, SocketCloseEventType, SocketDiagnostics, SocketDiagnosticsEventType } from 'vs/base/parts/ipc/common/ipc.net'; -import * as zlib from 'zlib'; + +// TODO@bpasero remove me once electron utility process has landed +function getNodeDependencies() { + return { + crypto: (require.__$__nodeRequire('crypto') as any) as typeof import('crypto'), + zlib: (require.__$__nodeRequire('zlib') as any) as typeof import('zlib'), + net: (require.__$__nodeRequire('net') as any) as typeof import('net'), + os: (require.__$__nodeRequire('os') as any) as typeof import('os') + }; +} export class NodeSocket implements ISocket { @@ -580,7 +590,7 @@ class ZlibInflateStream extends Disposable { options: zlib.ZlibOptions ) { super(); - this._zlibInflate = zlib.createInflateRaw(options); + this._zlibInflate = getNodeDependencies().zlib.createInflateRaw(options); this._zlibInflate.on('error', (err) => { this._tracer.traceSocketEvent(SocketDiagnosticsEventType.zlibInflateError, { message: err?.message, code: (err)?.code }); this._onError.fire(err); @@ -631,7 +641,7 @@ class ZlibDeflateStream extends Disposable { ) { super(); - this._zlibDeflate = zlib.createDeflateRaw({ + this._zlibDeflate = getNodeDependencies().zlib.createDeflateRaw({ windowBits: 15 }); this._zlibDeflate.on('error', (err) => { @@ -692,7 +702,8 @@ function unmask(buffer: VSBuffer, mask: number): void { // Read this before there's any chance it is overwritten // Related to https://github.com/microsoft/vscode/issues/30624 -export const XDG_RUNTIME_DIR = process.env['XDG_RUNTIME_DIR']; +// TODO@bpasero revert me once electron utility process has landed +export const XDG_RUNTIME_DIR = typeof process !== 'undefined' ? process.env['XDG_RUNTIME_DIR'] : undefined; const safeIpcPathLengths: { [platform: number]: number } = { [Platform.Linux]: 107, @@ -713,7 +724,7 @@ export function createRandomIPCHandle(): string { if (XDG_RUNTIME_DIR) { result = join(XDG_RUNTIME_DIR, `vscode-ipc-${randomSuffix}.sock`); } else { - result = join(tmpdir(), `vscode-ipc-${randomSuffix}.sock`); + result = join(getNodeDependencies().os.tmpdir(), `vscode-ipc-${randomSuffix}.sock`); } // Validate length @@ -723,7 +734,7 @@ export function createRandomIPCHandle(): string { } export function createStaticIPCHandle(directoryPath: string, type: string, version: string): string { - const scope = createHash('md5').update(directoryPath).digest('hex'); + const scope = getNodeDependencies().crypto.createHash('md5').update(directoryPath).digest('hex'); // Windows: use named pipe if (process.platform === 'win32') { @@ -785,7 +796,7 @@ export function serve(port: number): Promise; export function serve(namedPipe: string): Promise; export function serve(hook: any): Promise { return new Promise((c, e) => { - const server = createServer(); + const server = getNodeDependencies().net.createServer(); server.on('error', e); server.listen(hook, () => { @@ -800,7 +811,7 @@ export function connect(port: number, clientId: string): Promise; export function connect(namedPipe: string, clientId: string): Promise; export function connect(hook: any, clientId: string): Promise { return new Promise((c, e) => { - const socket = createConnection(hook, () => { + const socket = getNodeDependencies().net.createConnection(hook, () => { socket.removeListener('error', e); c(Client.fromSocket(new NodeSocket(socket, `ipc-client${clientId}`), clientId)); }); diff --git a/src/vs/base/parts/quickinput/browser/media/quickInput.css b/src/vs/base/parts/quickinput/browser/media/quickInput.css index efab21e77bf..e3357d75fe8 100644 --- a/src/vs/base/parts/quickinput/browser/media/quickInput.css +++ b/src/vs/base/parts/quickinput/browser/media/quickInput.css @@ -7,7 +7,6 @@ position: absolute; width: 600px; z-index: 2550; - padding: 0 1px 1px 1px; left: 50%; margin-left: -300px; -webkit-app-region: no-drag; @@ -151,6 +150,7 @@ .quick-input-list { line-height: 22px; margin-top: 6px; + padding: 0px 1px 1px 1px; } .quick-input-widget.hidden-input .quick-input-list { diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index 1a496080028..41e7da28efa 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -15,6 +15,7 @@ import { IKeybindingLabelStyles } from 'vs/base/browser/ui/keybindingLabel/keybi import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IListOptions, IListStyles, List } from 'vs/base/browser/ui/list/listWidget'; import { IProgressBarStyles, ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; +import { Toggle } from 'vs/base/browser/ui/toggle/toggle'; import { Action } from 'vs/base/common/actions'; import { equals } from 'vs/base/common/arrays'; import { TimeoutTimer } from 'vs/base/common/async'; @@ -28,7 +29,7 @@ import { isIOS } from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; import { isString, withNullAsUndefined } from 'vs/base/common/types'; import { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils'; -import { IInputBox, IInputOptions, IKeyMods, IPickOptions, IQuickInput, IQuickInputButton, IQuickInputHideEvent, IQuickNavigateConfiguration, IQuickPick, IQuickPickDidAcceptEvent, IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator, IQuickPickWillAcceptEvent, ItemActivation, NO_KEY_MODS, QuickInputHideReason, QuickPickInput } from 'vs/base/parts/quickinput/common/quickInput'; +import { IInputBox, IInputOptions, IKeyMods, IPickOptions, IQuickInput, IQuickInputButton, IQuickInputHideEvent, IQuickInputToggle, IQuickNavigateConfiguration, IQuickPick, IQuickPickDidAcceptEvent, IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator, IQuickPickWillAcceptEvent, ItemActivation, NO_KEY_MODS, QuickInputHideReason, QuickPickInput } from 'vs/base/parts/quickinput/common/quickInput'; import 'vs/css!./media/quickInput'; import { localize } from 'vs/nls'; import { QuickInputBox } from './quickInputBox'; @@ -450,6 +451,7 @@ class QuickPick extends QuickInput implements IQuickPi private _matchOnDescription = false; private _matchOnDetail = false; private _matchOnLabel = true; + private _matchOnLabelMode: 'fuzzy' | 'contiguous' = 'fuzzy'; private _sortByLabel = true; private _autoFocusOnList = true; private _keepScrollPosition = false; @@ -595,6 +597,15 @@ class QuickPick extends QuickInput implements IQuickPi this.update(); } + get matchOnLabelMode() { + return this._matchOnLabelMode; + } + + set matchOnLabelMode(matchOnLabelMode: 'fuzzy' | 'contiguous') { + this._matchOnLabelMode = matchOnLabelMode; + this.update(); + } + get sortByLabel() { return this._sortByLabel; } @@ -730,6 +741,14 @@ class QuickPick extends QuickInput implements IQuickPi this.update(); } + set toggles(toggles: IQuickInputToggle[] | undefined) { + // HACK: Filter out toggles here that are not concrete Toggle objects. This is to workaround + // a layering issue as quick input's interface is in common but Toggle is in browser and + // it requires a HTMLElement on its interface + const concreteToggles = toggles?.filter(opts => opts instanceof Toggle) as Toggle[]; + this.ui.inputBox.toggles = concreteToggles; + } + onDidChangeSelection = this.onDidChangeSelectionEmitter.event; onDidTriggerItemButton = this.onDidTriggerItemButtonEmitter.event; @@ -994,6 +1013,7 @@ class QuickPick extends QuickInput implements IQuickPi this.ui.list.matchOnDescription = this.matchOnDescription; this.ui.list.matchOnDetail = this.matchOnDetail; this.ui.list.matchOnLabel = this.matchOnLabel; + this.ui.list.matchOnLabelMode = this.matchOnLabelMode; this.ui.list.sortByLabel = this.sortByLabel; if (this.itemsUpdated) { this.itemsUpdated = false; @@ -1599,9 +1619,7 @@ export class QuickInputController extends Disposable { this.onShowEmitter.fire(); const oldController = this.controller; this.controller = controller; - if (oldController) { - oldController.didHide(); - } + oldController?.didHide(); this.setEnabled(true); ui.leftActionBar.clear(); @@ -1675,10 +1693,10 @@ export class QuickInputController extends Disposable { if (enabled !== this.enabled) { this.enabled = enabled; for (const item of this.getUI().leftActionBar.viewItems) { - (item as ActionViewItem).getAction().enabled = enabled; + (item as ActionViewItem).action.enabled = enabled; } for (const item of this.getUI().rightActionBar.viewItems) { - (item as ActionViewItem).getAction().enabled = enabled; + (item as ActionViewItem).action.enabled = enabled; } this.getUI().checkAll.disabled = !enabled; // this.getUI().inputBox.enabled = enabled; Avoid loosing focus. diff --git a/src/vs/base/parts/quickinput/browser/quickInputBox.ts b/src/vs/base/parts/quickinput/browser/quickInputBox.ts index a6d798bb3da..1184a456574 100644 --- a/src/vs/base/parts/quickinput/browser/quickInputBox.ts +++ b/src/vs/base/parts/quickinput/browser/quickInputBox.ts @@ -6,7 +6,9 @@ import * as dom from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { IInputBoxStyles, InputBox, IRange, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; +import { FindInput } from 'vs/base/browser/ui/findinput/findInput'; +import { IInputBoxStyles, IRange, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; +import { Toggle } from 'vs/base/browser/ui/toggle/toggle'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import Severity from 'vs/base/common/severity'; import 'vs/css!./media/quickInput'; @@ -16,113 +18,117 @@ const $ = dom.$; export class QuickInputBox extends Disposable { private container: HTMLElement; - private inputBox: InputBox; + private findInput: FindInput; constructor( private parent: HTMLElement ) { super(); this.container = dom.append(this.parent, $('.quick-input-box')); - this.inputBox = this._register(new InputBox(this.container, undefined)); + this.findInput = this._register(new FindInput(this.container, undefined, { label: '' })); } onKeyDown = (handler: (event: StandardKeyboardEvent) => void): IDisposable => { - return dom.addDisposableListener(this.inputBox.inputElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { + return dom.addDisposableListener(this.findInput.inputBox.inputElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { handler(new StandardKeyboardEvent(e)); }); }; onMouseDown = (handler: (event: StandardMouseEvent) => void): IDisposable => { - return dom.addDisposableListener(this.inputBox.inputElement, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => { + return dom.addDisposableListener(this.findInput.inputBox.inputElement, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => { handler(new StandardMouseEvent(e)); }); }; onDidChange = (handler: (event: string) => void): IDisposable => { - return this.inputBox.onDidChange(handler); + return this.findInput.onDidChange(handler); }; get value() { - return this.inputBox.value; + return this.findInput.getValue(); } set value(value: string) { - this.inputBox.value = value; + this.findInput.setValue(value); } select(range: IRange | null = null): void { - this.inputBox.select(range); + this.findInput.inputBox.select(range); } isSelectionAtEnd(): boolean { - return this.inputBox.isSelectionAtEnd(); + return this.findInput.inputBox.isSelectionAtEnd(); } setPlaceholder(placeholder: string): void { - this.inputBox.setPlaceHolder(placeholder); + this.findInput.inputBox.setPlaceHolder(placeholder); } get placeholder() { - return this.inputBox.inputElement.getAttribute('placeholder') || ''; + return this.findInput.inputBox.inputElement.getAttribute('placeholder') || ''; } set placeholder(placeholder: string) { - this.inputBox.setPlaceHolder(placeholder); + this.findInput.inputBox.setPlaceHolder(placeholder); } get ariaLabel() { - return this.inputBox.getAriaLabel(); + return this.findInput.inputBox.getAriaLabel(); } set ariaLabel(ariaLabel: string) { - this.inputBox.setAriaLabel(ariaLabel); + this.findInput.inputBox.setAriaLabel(ariaLabel); } get password() { - return this.inputBox.inputElement.type === 'password'; + return this.findInput.inputBox.inputElement.type === 'password'; } set password(password: boolean) { - this.inputBox.inputElement.type = password ? 'password' : 'text'; + this.findInput.inputBox.inputElement.type = password ? 'password' : 'text'; } set enabled(enabled: boolean) { - this.inputBox.setEnabled(enabled); + this.findInput.setEnabled(enabled); + } + + set toggles(toggles: Toggle[] | undefined) { + this.findInput.setAdditionalToggles(toggles); } hasFocus(): boolean { - return this.inputBox.hasFocus(); + return this.findInput.inputBox.hasFocus(); } setAttribute(name: string, value: string): void { - this.inputBox.inputElement.setAttribute(name, value); + this.findInput.inputBox.inputElement.setAttribute(name, value); } removeAttribute(name: string): void { - this.inputBox.inputElement.removeAttribute(name); + this.findInput.inputBox.inputElement.removeAttribute(name); } showDecoration(decoration: Severity): void { if (decoration === Severity.Ignore) { - this.inputBox.hideMessage(); + this.findInput.clearMessage(); } else { - this.inputBox.showMessage({ type: decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR, content: '' }); + this.findInput.showMessage({ type: decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR, content: '' }); } } stylesForType(decoration: Severity) { - return this.inputBox.stylesForType(decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR); + return this.findInput.inputBox.stylesForType(decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR); } setFocus(): void { - this.inputBox.focus(); + this.findInput.focus(); } layout(): void { - this.inputBox.layout(); + this.findInput.inputBox.layout(); } style(styles: IInputBoxStyles): void { - this.inputBox.style(styles); + this.findInput.style(styles); } } diff --git a/src/vs/base/parts/quickinput/browser/quickInputList.ts b/src/vs/base/parts/quickinput/browser/quickInputList.ts index 2ada8ddcc60..25058c9de25 100644 --- a/src/vs/base/parts/quickinput/browser/quickInputList.ts +++ b/src/vs/base/parts/quickinput/browser/quickInputList.ts @@ -17,14 +17,15 @@ import { compareAnything } from 'vs/base/common/comparers'; import { memoize } from 'vs/base/common/decorators'; import { Emitter, Event } from 'vs/base/common/event'; import { IMatch } from 'vs/base/common/filters'; -import { matchesFuzzyIconAware, parseLabelWithIcons } from 'vs/base/common/iconLabels'; +import { IParsedLabelWithIcons, matchesFuzzyIconAware, parseLabelWithIcons } from 'vs/base/common/iconLabels'; import { KeyCode } from 'vs/base/common/keyCodes'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; +import { ltrim } from 'vs/base/common/strings'; import { withNullAsUndefined } from 'vs/base/common/types'; import { IQuickInputOptions } from 'vs/base/parts/quickinput/browser/quickInput'; import { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils'; -import { IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator } from 'vs/base/parts/quickinput/common/quickInput'; +import { QuickPickItem, IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator } from 'vs/base/parts/quickinput/common/quickInput'; import 'vs/css!./media/quickInput'; import { localize } from 'vs/nls'; @@ -252,12 +253,13 @@ export class QuickInputList { readonly id: string; private container: HTMLElement; private list: List; - private inputElements: Array = []; + private inputElements: Array = []; private elements: ListElement[] = []; private elementsToIndexes = new Map(); matchOnDescription = false; matchOnDetail = false; matchOnLabel = true; + matchOnLabelMode: 'fuzzy' | 'contiguous' = 'fuzzy'; matchOnMeta = true; sortByLabel = true; private readonly _onChangedAllVisibleChecked = new Emitter(); @@ -434,7 +436,7 @@ export class QuickInputList { } } - setElements(inputElements: Array): void { + setElements(inputElements: Array): void { this.elementDisposables = dispose(this.elementDisposables); const fireButtonTriggered = (event: IQuickPickItemButtonEvent) => this.fireButtonTriggered(event); this.inputElements = inputElements; @@ -610,6 +612,8 @@ export class QuickInputList { this.list.layout(); return false; } + + const queryWithWhitespace = query; query = query.trim(); // Reset filtering @@ -628,7 +632,12 @@ export class QuickInputList { else { let currentSeparator: IQuickPickSeparator | undefined; this.elements.forEach(element => { - const labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneLabel))) : undefined; + let labelHighlights: IMatch[] | undefined; + if (this.matchOnLabelMode === 'fuzzy') { + labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneLabel))) : undefined; + } else { + labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesContiguousIconAware(queryWithWhitespace, parseLabelWithIcons(element.saneLabel))) : undefined; + } const descriptionHighlights = this.matchOnDescription ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneDescription || ''))) : undefined; const detailHighlights = this.matchOnDetail ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneDetail || ''))) : undefined; const metaHighlights = this.matchOnMeta ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneMeta || ''))) : undefined; @@ -726,6 +735,43 @@ export class QuickInputList { } } +export function matchesContiguousIconAware(query: string, target: IParsedLabelWithIcons): IMatch[] | null { + + const { text, iconOffsets } = target; + + // Return early if there are no icon markers in the word to match against + if (!iconOffsets || iconOffsets.length === 0) { + return matchesContiguous(query, text); + } + + // Trim the word to match against because it could have leading + // whitespace now if the word started with an icon + const wordToMatchAgainstWithoutIconsTrimmed = ltrim(text, ' '); + const leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutIconsTrimmed.length; + + // match on value without icon + const matches = matchesContiguous(query, wordToMatchAgainstWithoutIconsTrimmed); + + // Map matches back to offsets with icon and trimming + if (matches) { + for (const match of matches) { + const iconOffset = iconOffsets[match.start + leadingWhitespaceOffset] /* icon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */; + match.start += iconOffset; + match.end += iconOffset; + } + } + + return matches; +} + +function matchesContiguous(word: string, wordToMatchAgainst: string): IMatch[] | null { + const matchIndex = wordToMatchAgainst.toLowerCase().indexOf(word.toLowerCase()); + if (matchIndex !== -1) { + return [{ start: matchIndex, end: matchIndex + word.length }]; + } + return null; +} + function compareEntries(elementA: ListElement, elementB: ListElement, lookFor: string): number { const labelHighlightsA = elementA.labelHighlights || []; diff --git a/src/vs/base/parts/quickinput/common/quickInput.ts b/src/vs/base/parts/quickinput/common/quickInput.ts index bf9979e00b1..f86a4c00817 100644 --- a/src/vs/base/parts/quickinput/common/quickInput.ts +++ b/src/vs/base/parts/quickinput/common/quickInput.ts @@ -18,6 +18,8 @@ export interface IQuickPickItemHighlights { detail?: IMatch[]; } +export type QuickPickItem = IQuickPickSeparator | IQuickPickItem; + export interface IQuickPickItem { type?: 'item'; id?: string; @@ -292,6 +294,13 @@ export interface IQuickPick extends IQuickInput { matchOnLabel: boolean; + /** + * The mode to filter label with. Fuzzy will use fuzzy searching and + * contiguous will make filter entries that do not contain the exact string + * (including whitespace). This defaults to `'fuzzy'`. + */ + matchOnLabelMode: 'fuzzy' | 'contiguous'; + sortByLabel: boolean; autoFocusOnList: boolean; @@ -331,30 +340,73 @@ export interface IQuickPick extends IQuickInput { hideInput: boolean; hideCheckAll: boolean; + + /** + * A set of `Toggle` objects to add to the input box. + */ + toggles: IQuickInputToggle[] | undefined; +} + +export interface IQuickInputToggle { + onChange: Event; } export interface IInputBox extends IQuickInput { + /** + * Value shown in the input box. + */ value: string; + /** + * Provide start and end values to be selected in the input box. + */ valueSelection: Readonly<[number, number]> | undefined; + /** + * Value shown as example for input. + */ placeholder: string | undefined; + /** + * Determines if the input value should be hidden while typing. + */ password: boolean; + /** + * Event called when the input value changes. + */ readonly onDidChangeValue: Event; + /** + * Event called when the user submits the input. + */ readonly onDidAccept: Event; + /** + * Buttons to show in addition to user input submission. + */ buttons: ReadonlyArray; + /** + * Event called when a button is selected. + */ readonly onDidTriggerButton: Event; + /** + * Text show below the input box. + */ prompt: string | undefined; + /** + * An optional validation message indicating a problem with the current input value. + * Returning undefined clears the validation message. + */ validationMessage: string | undefined; + /** + * Severity of the input validation message. + */ severity: Severity; } diff --git a/src/vs/base/parts/quickinput/test/browser/quickinput.test.ts b/src/vs/base/parts/quickinput/test/browser/quickinput.test.ts index 89f2f212dd4..dc99756b291 100644 --- a/src/vs/base/parts/quickinput/test/browser/quickinput.test.ts +++ b/src/vs/base/parts/quickinput/test/browser/quickinput.test.ts @@ -39,7 +39,7 @@ suite('QuickInput', () => { // https://github.com/microsoft/vscode/issues/147543 controller = new QuickInputController({ container: fixture, idPrefix: 'testQuickInput', - ignoreFocusOut() { return false; }, + ignoreFocusOut() { return true; }, isScreenReaderOptimized() { return false; }, returnFocus() { }, backKeybindingLabel() { return undefined; }, @@ -80,7 +80,7 @@ suite('QuickInput', () => { // https://github.com/microsoft/vscode/issues/147543 await wait; controller.accept(); - const pick = await pickPromise; + const pick = await raceTimeout(pickPromise, 2000); assert.strictEqual(pick, item); }); @@ -104,7 +104,7 @@ suite('QuickInput', () => { // https://github.com/microsoft/vscode/issues/147543 await wait; controller.accept(); - const value = await inputPromise; + const value = await raceTimeout(inputPromise, 2000); assert.strictEqual(value, 'foo'); }); diff --git a/src/vs/base/parts/sandbox/electron-browser/preload.js b/src/vs/base/parts/sandbox/electron-browser/preload.js index 3e25c4097f1..53e38ce14c2 100644 --- a/src/vs/base/parts/sandbox/electron-browser/preload.js +++ b/src/vs/base/parts/sandbox/electron-browser/preload.js @@ -145,7 +145,7 @@ /** * @param {string} channel * @param {any[]} args - * @returns {Promise | undefined} + * @returns {Promise | never} */ invoke(channel, ...args) { if (validateIPC(channel)) { @@ -156,7 +156,7 @@ /** * @param {string} channel * @param {(event: IpcRendererEvent, ...args: any[]) => void} listener - * @returns {IpcRenderer} + * @returns {IpcRenderer | never} */ on(channel, listener) { if (validateIPC(channel)) { @@ -169,7 +169,7 @@ /** * @param {string} channel * @param {(event: IpcRendererEvent, ...args: any[]) => void} listener - * @returns {IpcRenderer} + * @returns {IpcRenderer | never} */ once(channel, listener) { if (validateIPC(channel)) { @@ -182,7 +182,7 @@ /** * @param {string} channel * @param {(event: IpcRendererEvent, ...args: any[]) => void} listener - * @returns {IpcRenderer} + * @returns {IpcRenderer | never} */ removeListener(channel, listener) { if (validateIPC(channel)) { diff --git a/src/vs/base/parts/sandbox/electron-sandbox/globals.ts b/src/vs/base/parts/sandbox/electron-sandbox/globals.ts index 7d9b29a6e3a..d89c22a4f0d 100644 --- a/src/vs/base/parts/sandbox/electron-sandbox/globals.ts +++ b/src/vs/base/parts/sandbox/electron-sandbox/globals.ts @@ -36,6 +36,10 @@ export interface ISandboxNodeProcess extends INodeProcess { /** * The `process.pid` property returns the PID of the process. + * + * @deprecated this property will be removed once sandbox is enabled. + * + * TODO@bpasero remove this property when sandbox is on */ readonly pid: number; diff --git a/src/vs/base/parts/storage/test/node/storage.test.ts b/src/vs/base/parts/storage/test/node/storage.test.ts index f53fdb2c387..70ff91977be 100644 --- a/src/vs/base/parts/storage/test/node/storage.test.ts +++ b/src/vs/base/parts/storage/test/node/storage.test.ts @@ -670,56 +670,57 @@ flakySuite('SQLite Storage Library', function () { }); test('multiple concurrent writes execute in sequence', async () => { - - class TestStorage extends Storage { - getStorage(): IStorageDatabase { - return this.database; + return runWithFakedTimers({}, async () => { + class TestStorage extends Storage { + getStorage(): IStorageDatabase { + return this.database; + } } - } - const storage = new TestStorage(new SQLiteStorageDatabase(join(testdir, 'storage.db'))); + const storage = new TestStorage(new SQLiteStorageDatabase(join(testdir, 'storage.db'))); - await storage.init(); + await storage.init(); - storage.set('foo', 'bar'); - storage.set('some/foo/path', 'some/bar/path'); + storage.set('foo', 'bar'); + storage.set('some/foo/path', 'some/bar/path'); - await timeout(2); + await timeout(2); - storage.set('foo1', 'bar'); - storage.set('some/foo1/path', 'some/bar/path'); + storage.set('foo1', 'bar'); + storage.set('some/foo1/path', 'some/bar/path'); - await timeout(2); + await timeout(2); - storage.set('foo2', 'bar'); - storage.set('some/foo2/path', 'some/bar/path'); + storage.set('foo2', 'bar'); + storage.set('some/foo2/path', 'some/bar/path'); - await timeout(2); + await timeout(2); - storage.delete('foo1'); - storage.delete('some/foo1/path'); + storage.delete('foo1'); + storage.delete('some/foo1/path'); - await timeout(2); + await timeout(2); - storage.delete('foo4'); - storage.delete('some/foo4/path'); + storage.delete('foo4'); + storage.delete('some/foo4/path'); - await timeout(5); + await timeout(5); - storage.set('foo3', 'bar'); - await storage.set('some/foo3/path', 'some/bar/path'); + storage.set('foo3', 'bar'); + await storage.set('some/foo3/path', 'some/bar/path'); - const items = await storage.getStorage().getItems(); - strictEqual(items.get('foo'), 'bar'); - strictEqual(items.get('some/foo/path'), 'some/bar/path'); - strictEqual(items.has('foo1'), false); - strictEqual(items.has('some/foo1/path'), false); - strictEqual(items.get('foo2'), 'bar'); - strictEqual(items.get('some/foo2/path'), 'some/bar/path'); - strictEqual(items.get('foo3'), 'bar'); - strictEqual(items.get('some/foo3/path'), 'some/bar/path'); + const items = await storage.getStorage().getItems(); + strictEqual(items.get('foo'), 'bar'); + strictEqual(items.get('some/foo/path'), 'some/bar/path'); + strictEqual(items.has('foo1'), false); + strictEqual(items.has('some/foo1/path'), false); + strictEqual(items.get('foo2'), 'bar'); + strictEqual(items.get('some/foo2/path'), 'some/bar/path'); + strictEqual(items.get('foo3'), 'bar'); + strictEqual(items.get('some/foo3/path'), 'some/bar/path'); - await storage.close(); + await storage.close(); + }); }); test('lots of INSERT & DELETE (below inline max)', async () => { diff --git a/src/vs/base/test/browser/dom.test.ts b/src/vs/base/test/browser/dom.test.ts index 435f0066b9c..1ad53561927 100644 --- a/src/vs/base/test/browser/dom.test.ts +++ b/src/vs/base/test/browser/dom.test.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import * as dom from 'vs/base/browser/dom'; -const $ = dom.$; +import { $, h, multibyteAwareBtoa } from 'vs/base/browser/dom'; suite('dom', () => { test('hasClass', () => { @@ -73,9 +72,9 @@ suite('dom', () => { }); test('multibyteAwareBtoa', () => { - assert.ok(dom.multibyteAwareBtoa('hello world').length > 0); - assert.ok(dom.multibyteAwareBtoa('平仮名').length > 0); - assert.ok(dom.multibyteAwareBtoa(new Array(100000).fill('vs').join('')).length > 0); // https://github.com/microsoft/vscode/issues/112013 + assert.ok(multibyteAwareBtoa('hello world').length > 0); + assert.ok(multibyteAwareBtoa('平仮名').length > 0); + assert.ok(multibyteAwareBtoa(new Array(100000).fill('vs').join('')).length > 0); // https://github.com/microsoft/vscode/issues/112013 }); suite('$', () => { @@ -129,4 +128,152 @@ suite('dom', () => { assert.strictEqual(firstChild.textContent, 'foobar'); }); }); + + suite('h', () => { + test('should build simple nodes', () => { + const div = h('div'); + assert(div.root instanceof HTMLElement); + assert.strictEqual(div.root.tagName, 'DIV'); + + const span = h('span'); + assert(span.root instanceof HTMLElement); + assert.strictEqual(span.root.tagName, 'SPAN'); + + const img = h('img'); + assert(img.root instanceof HTMLElement); + assert.strictEqual(img.root.tagName, 'IMG'); + }); + + test('should handle ids and classes', () => { + const divId = h('div#myid'); + assert.strictEqual(divId.root.tagName, 'DIV'); + assert.strictEqual(divId.root.id, 'myid'); + + const divClass = h('div.a'); + assert.strictEqual(divClass.root.tagName, 'DIV'); + assert.strictEqual(divClass.root.classList.length, 1); + assert(divClass.root.classList.contains('a')); + + const divClasses = h('div.a.b.c'); + assert.strictEqual(divClasses.root.tagName, 'DIV'); + assert.strictEqual(divClasses.root.classList.length, 3); + assert(divClasses.root.classList.contains('a')); + assert(divClasses.root.classList.contains('b')); + assert(divClasses.root.classList.contains('c')); + + const divAll = h('div#myid.a.b.c'); + assert.strictEqual(divAll.root.tagName, 'DIV'); + assert.strictEqual(divAll.root.id, 'myid'); + assert.strictEqual(divAll.root.classList.length, 3); + assert(divAll.root.classList.contains('a')); + assert(divAll.root.classList.contains('b')); + assert(divAll.root.classList.contains('c')); + + const spanId = h('span#myid'); + assert.strictEqual(spanId.root.tagName, 'SPAN'); + assert.strictEqual(spanId.root.id, 'myid'); + + const spanClass = h('span.a'); + assert.strictEqual(spanClass.root.tagName, 'SPAN'); + assert.strictEqual(spanClass.root.classList.length, 1); + assert(spanClass.root.classList.contains('a')); + + const spanClasses = h('span.a.b.c'); + assert.strictEqual(spanClasses.root.tagName, 'SPAN'); + assert.strictEqual(spanClasses.root.classList.length, 3); + assert(spanClasses.root.classList.contains('a')); + assert(spanClasses.root.classList.contains('b')); + assert(spanClasses.root.classList.contains('c')); + + const spanAll = h('span#myid.a.b.c'); + assert.strictEqual(spanAll.root.tagName, 'SPAN'); + assert.strictEqual(spanAll.root.id, 'myid'); + assert.strictEqual(spanAll.root.classList.length, 3); + assert(spanAll.root.classList.contains('a')); + assert(spanAll.root.classList.contains('b')); + assert(spanAll.root.classList.contains('c')); + }); + + test('should implicitly handle ids and classes', () => { + const divId = h('#myid'); + assert.strictEqual(divId.root.tagName, 'DIV'); + assert.strictEqual(divId.root.id, 'myid'); + + const divClass = h('.a'); + assert.strictEqual(divClass.root.tagName, 'DIV'); + assert.strictEqual(divClass.root.classList.length, 1); + assert(divClass.root.classList.contains('a')); + + const divClasses = h('.a.b.c'); + assert.strictEqual(divClasses.root.tagName, 'DIV'); + assert.strictEqual(divClasses.root.classList.length, 3); + assert(divClasses.root.classList.contains('a')); + assert(divClasses.root.classList.contains('b')); + assert(divClasses.root.classList.contains('c')); + + const divAll = h('#myid.a.b.c'); + assert.strictEqual(divAll.root.tagName, 'DIV'); + assert.strictEqual(divAll.root.id, 'myid'); + assert.strictEqual(divAll.root.classList.length, 3); + assert(divAll.root.classList.contains('a')); + assert(divAll.root.classList.contains('b')); + assert(divAll.root.classList.contains('c')); + }); + + test('should handle @ identifiers', () => { + const implicit = h('@el'); + assert.strictEqual(implicit.root, implicit.el); + assert.strictEqual(implicit.el.tagName, 'DIV'); + + const explicit = h('div@el'); + assert.strictEqual(explicit.root, explicit.el); + assert.strictEqual(explicit.el.tagName, 'DIV'); + + const implicitId = h('#myid@el'); + assert.strictEqual(implicitId.root, implicitId.el); + assert.strictEqual(implicitId.el.tagName, 'DIV'); + assert.strictEqual(implicitId.root.id, 'myid'); + + const explicitId = h('div#myid@el'); + assert.strictEqual(explicitId.root, explicitId.el); + assert.strictEqual(explicitId.el.tagName, 'DIV'); + assert.strictEqual(explicitId.root.id, 'myid'); + + const implicitClass = h('.a@el'); + assert.strictEqual(implicitClass.root, implicitClass.el); + assert.strictEqual(implicitClass.el.tagName, 'DIV'); + assert.strictEqual(implicitClass.root.classList.length, 1); + assert(implicitClass.root.classList.contains('a')); + + const explicitClass = h('div.a@el'); + assert.strictEqual(explicitClass.root, explicitClass.el); + assert.strictEqual(explicitClass.el.tagName, 'DIV'); + assert.strictEqual(explicitClass.root.classList.length, 1); + assert(explicitClass.root.classList.contains('a')); + }); + }); + + test('should recurse', () => { + const result = h('div.code-view', [ + h('div.title@title'), + h('div.container', [ + h('div.gutter@gutterDiv'), + h('span@editor'), + ]), + ]); + + assert.strictEqual(result.root.tagName, 'DIV'); + assert.strictEqual(result.root.className, 'code-view'); + assert.strictEqual(result.root.childElementCount, 2); + assert.strictEqual(result.root.firstElementChild, result.title); + assert.strictEqual(result.title.tagName, 'DIV'); + assert.strictEqual(result.title.className, 'title'); + assert.strictEqual(result.title.childElementCount, 0); + assert.strictEqual(result.gutterDiv.tagName, 'DIV'); + assert.strictEqual(result.gutterDiv.className, 'gutter'); + assert.strictEqual(result.gutterDiv.childElementCount, 0); + assert.strictEqual(result.editor.tagName, 'SPAN'); + assert.strictEqual(result.editor.className, ''); + assert.strictEqual(result.editor.childElementCount, 0); + }); }); diff --git a/src/vs/base/test/browser/indexedDB.test.ts b/src/vs/base/test/browser/indexedDB.test.ts index 581b6719148..ba9dcd0f51c 100644 --- a/src/vs/base/test/browser/indexedDB.test.ts +++ b/src/vs/base/test/browser/indexedDB.test.ts @@ -16,9 +16,7 @@ flakySuite('IndexedDB', () => { }); teardown(() => { - if (indexedDB) { - indexedDB.close(); - } + indexedDB?.close(); }); test('runInTransaction', async () => { diff --git a/src/vs/base/test/browser/markdownRenderer.test.ts b/src/vs/base/test/browser/markdownRenderer.test.ts index 3852b15797e..f30fc44b962 100644 --- a/src/vs/base/test/browser/markdownRenderer.test.ts +++ b/src/vs/base/test/browser/markdownRenderer.test.ts @@ -68,7 +68,7 @@ suite('MarkdownRenderer', () => { }); suite('Code block renderer', () => { - const simpleCodeBlockRenderer = (code: string): Promise => { + const simpleCodeBlockRenderer = (lang: string, code: string): Promise => { const element = document.createElement('code'); element.textContent = code; return Promise.resolve(element); @@ -115,6 +115,19 @@ suite('MarkdownRenderer', () => { }, 50); }); }); + + test('Code blocks should use leading language id (#157793)', async () => { + const markdown = { value: '```js some other stuff\n1 + 1;\n```' }; + const lang = await new Promise(resolve => { + renderMarkdown(markdown, { + codeBlockRenderer: async (lang, value) => { + resolve(lang); + return simpleCodeBlockRenderer(lang, value); + } + }); + }); + assert.strictEqual(lang, 'js'); + }); }); suite('ThemeIcons Support On', () => { diff --git a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts index 2fc37090431..d10d76b0b85 100644 --- a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts @@ -8,6 +8,7 @@ import { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { IAsyncDataSource, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; import { timeout } from 'vs/base/common/async'; +import { Iterable } from 'vs/base/common/iterator'; interface Element { id: string; @@ -435,4 +436,60 @@ suite('AsyncDataTree', function () { assert.deepStrictEqual(Array.from(container.querySelectorAll('.monaco-list-row')).map(e => e.textContent), ['a', 'b2']); }); + + test('issue #121567', async () => { + const container = document.createElement('div'); + + const calls: Element[] = []; + const dataSource = new class implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + async getChildren(element: Element) { + calls.push(element); + return element.children ?? Iterable.empty(); + } + }; + + const model = new Model({ + id: 'root', + children: [{ + id: 'a', children: [{ + id: 'aa' + }] + }] + }); + const a = model.get('a'); + + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); + tree.layout(200); + + await tree.setInput(model.root); + assert.strictEqual(calls.length, 1, 'There should be a single getChildren call for the root'); + assert(tree.isCollapsible(a), 'a is collapsible'); + assert(tree.isCollapsed(a), 'a is collapsed'); + + await tree.updateChildren(a, false); + assert.strictEqual(calls.length, 1, 'There should be no changes to the calls list, since a was collapsed'); + assert(tree.isCollapsible(a), 'a is collapsible'); + assert(tree.isCollapsed(a), 'a is collapsed'); + + const children = a.children; + a.children = []; + await tree.updateChildren(a, false); + assert.strictEqual(calls.length, 1, 'There should still be no changes to the calls list, since a was collapsed'); + assert(!tree.isCollapsible(a), 'a is no longer collapsible'); + assert(tree.isCollapsed(a), 'a is collapsed'); + + a.children = children; + await tree.updateChildren(a, false); + assert.strictEqual(calls.length, 1, 'There should still be no changes to the calls list, since a was collapsed'); + assert(tree.isCollapsible(a), 'a is collapsible again'); + assert(tree.isCollapsed(a), 'a is collapsed'); + + await tree.expand(a); + assert.strictEqual(calls.length, 2, 'Finally, there should be a getChildren call for a'); + assert(tree.isCollapsible(a), 'a is still collapsible'); + assert(!tree.isCollapsed(a), 'a is expanded'); + }); }); 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 91e83ec4476..9ae0e08b0f1 100644 --- a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts +++ b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts @@ -358,7 +358,7 @@ suite('IndexTreeModel', () => { assert.deepStrictEqual(list.length, 3); - model.setCollapsed([0], false); + model.expandTo([0, 1]); assert.deepStrictEqual(list.length, 6); assert.deepStrictEqual(list[0].element, 0); assert.deepStrictEqual(list[0].collapsed, false); diff --git a/src/vs/base/test/common/arrays.test.ts b/src/vs/base/test/common/arrays.test.ts index 4519661b5c9..23e2b720421 100644 --- a/src/vs/base/test/common/arrays.test.ts +++ b/src/vs/base/test/common/arrays.test.ts @@ -6,6 +6,19 @@ import * as assert from 'assert'; import * as arrays from 'vs/base/common/arrays'; suite('Arrays', () => { + + test('removeFastWithoutKeepingOrder', () => { + const array = [1, 4, 5, 7, 55, 59, 60, 61, 64, 69]; + arrays.removeFastWithoutKeepingOrder(array, 1); + assert.deepStrictEqual(array, [1, 69, 5, 7, 55, 59, 60, 61, 64]); + + arrays.removeFastWithoutKeepingOrder(array, 0); + assert.deepStrictEqual(array, [64, 69, 5, 7, 55, 59, 60, 61]); + + arrays.removeFastWithoutKeepingOrder(array, 7); + assert.deepStrictEqual(array, [64, 69, 5, 7, 55, 59, 60]); + }); + test('findFirst', () => { const array = [1, 4, 5, 7, 55, 59, 60, 61, 64, 69]; diff --git a/src/vs/base/test/common/async.test.ts b/src/vs/base/test/common/async.test.ts index 1939932aade..a63ba7b9897 100644 --- a/src/vs/base/test/common/async.test.ts +++ b/src/vs/base/test/common/async.test.ts @@ -667,6 +667,7 @@ suite('Async', () => { const sequentializer = new async.TaskSequentializer(); assert.ok(!sequentializer.hasPending()); + assert.ok(!sequentializer.hasNext()); assert.ok(!sequentializer.hasPending(2323)); assert.ok(!sequentializer.pending); @@ -675,11 +676,13 @@ suite('Async', () => { assert.ok(!sequentializer.hasPending()); assert.ok(!sequentializer.hasPending(1)); assert.ok(!sequentializer.pending); + assert.ok(!sequentializer.hasNext()); // pending removes itself after done (use async.timeout) sequentializer.setPending(2, async.timeout(1)); assert.ok(sequentializer.hasPending()); assert.ok(sequentializer.hasPending(2)); + assert.ok(!sequentializer.hasNext()); assert.strictEqual(sequentializer.hasPending(1), false); assert.ok(sequentializer.pending); @@ -699,9 +702,12 @@ suite('Async', () => { let nextDone = false; const res = sequentializer.setNext(() => Promise.resolve(null).then(() => { nextDone = true; return; })); + assert.ok(sequentializer.hasNext()); + await res; assert.ok(pendingDone); assert.ok(nextDone); + assert.ok(!sequentializer.hasNext()); }); test('pending and next (finishes after timeout)', async function () { @@ -717,6 +723,42 @@ suite('Async', () => { await res; assert.ok(pendingDone); assert.ok(nextDone); + assert.ok(!sequentializer.hasNext()); + }); + + test('join (without next or pending)', async function () { + const sequentializer = new async.TaskSequentializer(); + + await sequentializer.join(); + assert.ok(!sequentializer.hasNext()); + }); + + test('join (without next)', async function () { + const sequentializer = new async.TaskSequentializer(); + + let pendingDone = false; + sequentializer.setPending(1, async.timeout(1).then(() => { pendingDone = true; return; })); + + await sequentializer.join(); + assert.ok(pendingDone); + assert.ok(!sequentializer.hasPending()); + }); + + test('join (with next and pending)', async function () { + const sequentializer = new async.TaskSequentializer(); + + let pendingDone = false; + sequentializer.setPending(1, async.timeout(1).then(() => { pendingDone = true; return; })); + + // next finishes after async.timeout + let nextDone = false; + sequentializer.setNext(() => async.timeout(1).then(() => { nextDone = true; return; })); + + await sequentializer.join(); + assert.ok(pendingDone); + assert.ok(nextDone); + assert.ok(!sequentializer.hasPending()); + assert.ok(!sequentializer.hasNext()); }); test('pending and multiple next (last one wins)', async function () { diff --git a/src/vs/base/test/common/collections.test.ts b/src/vs/base/test/common/collections.test.ts index 138d7486390..9dfe59a58fe 100644 --- a/src/vs/base/test/common/collections.test.ts +++ b/src/vs/base/test/common/collections.test.ts @@ -8,27 +8,6 @@ import * as collections from 'vs/base/common/collections'; suite('Collections', () => { - test('forEach', () => { - collections.forEach({}, () => assert(false)); - collections.forEach(Object.create(null), () => assert(false)); - - let count = 0; - collections.forEach({ toString: 123 }, () => count++); - assert.strictEqual(count, 1); - - count = 0; - const dict = Object.create(null); - dict['toString'] = 123; - collections.forEach(dict, () => count++); - assert.strictEqual(count, 1); - - collections.forEach(dict, () => false); - - // don't iterate over properties that are not on the object itself - const test = Object.create({ 'derived': true }); - collections.forEach(test, () => assert(false)); - }); - test('groupBy', () => { const group1 = 'a', group2 = 'b'; diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index a34566c10f1..39d878bce5d 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -8,7 +8,8 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { errorHandler, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { AsyncEmitter, DebounceEmitter, Emitter, Event, EventBufferer, EventMultiplexer, IWaitUntil, MicrotaskEmitter, PauseableEmitter, Relay } from 'vs/base/common/event'; import { DisposableStore, IDisposable, isDisposable, setDisposableTracker, toDisposable } from 'vs/base/common/lifecycle'; -import { DisposableTracker } from 'vs/base/test/common/utils'; +import { observableValue, transaction } from 'vs/base/common/observable'; +import { DisposableTracker, ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; namespace Samples { @@ -624,6 +625,33 @@ suite('PausableEmitter', function () { }); }); +suite('Event utils - ensureNoDisposablesAreLeakedInTestSuite', function () { + ensureNoDisposablesAreLeakedInTestSuite(); + + test('fromObservable', function () { + + const obs = observableValue('test', 12); + const event = Event.fromObservable(obs); + + const values: number[] = []; + const d = event(n => { values.push(n); }); + + obs.set(3, undefined); + obs.set(13, undefined); + obs.set(3, undefined); + obs.set(33, undefined); + obs.set(1, undefined); + + transaction(tx => { + obs.set(334, tx); + obs.set(99, tx); + }); + + assert.deepStrictEqual(values, ([3, 13, 3, 33, 1, 99])); + d.dispose(); + }); +}); + suite('Event utils', () => { suite('EventBufferer', () => { diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index 8b890f21662..29754cc4eed 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -185,24 +185,28 @@ suite('Filters', () => { assert(matchesWords('Debug Console', 'Open: Debug Console')); filterOk(matchesWords, 'gp', 'Git: Pull', [{ start: 0, end: 1 }, { start: 5, end: 6 }]); - filterOk(matchesWords, 'g p', 'Git: Pull', [{ start: 0, end: 1 }, { start: 3, end: 4 }, { start: 5, end: 6 }]); + filterOk(matchesWords, 'g p', 'Git: Pull', [{ start: 0, end: 1 }, { start: 5, end: 6 }]); filterOk(matchesWords, 'gipu', 'Git: Pull', [{ start: 0, end: 2 }, { start: 5, end: 7 }]); filterOk(matchesWords, 'gp', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 15, end: 16 }]); - filterOk(matchesWords, 'g p', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 13, end: 14 }, { start: 15, end: 16 }]); + filterOk(matchesWords, 'g p', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 15, end: 16 }]); filterOk(matchesWords, 'gipu', 'Category: Git: Pull', [{ start: 10, end: 12 }, { start: 15, end: 17 }]); filterNotOk(matchesWords, 'it', 'Git: Pull'); filterNotOk(matchesWords, 'll', 'Git: Pull'); filterOk(matchesWords, 'git: プル', 'git: プル', [{ start: 0, end: 7 }]); - filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 4 }, { start: 5, end: 7 }]); + filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 3 }, { start: 5, end: 7 }]); filterOk(matchesWords, 'öäk', 'Öhm: Älles Klar', [{ start: 0, end: 1 }, { start: 5, end: 6 }, { start: 11, end: 12 }]); // Handles issue #123915 filterOk(matchesWords, 'C++', 'C/C++: command', [{ start: 2, end: 5 }]); + // Handles issue #154533 + filterOk(matchesWords, '.', ':', []); + filterOk(matchesWords, '.', '.', [{ start: 0, end: 1 }]); + // assert.ok(matchesWords('gipu', 'Category: Git: Pull', true) === null); // assert.deepStrictEqual(matchesWords('pu', 'Category: Git: Pull', true), [{ start: 15, end: 17 }]); diff --git a/src/vs/base/test/common/lifecycle.test.ts b/src/vs/base/test/common/lifecycle.test.ts index 07437bf8ef7..b3d97a77a9c 100644 --- a/src/vs/base/test/common/lifecycle.test.ts +++ b/src/vs/base/test/common/lifecycle.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { Emitter } from 'vs/base/common/event'; -import { DisposableStore, dispose, IDisposable, markAsSingleton, MultiDisposeError, ReferenceCollection, SafeDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, dispose, IDisposable, markAsSingleton, ReferenceCollection, SafeDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ensureNoDisposablesAreLeakedInTestSuite, throwIfDisposablesAreLeaked } from 'vs/base/test/common/utils'; class Disposable implements IDisposable { @@ -88,10 +88,10 @@ suite('Lifecycle', () => { assert.ok(disposedValues.has(1)); assert.ok(disposedValues.has(4)); - assert.ok(thrownError instanceof MultiDisposeError); - assert.strictEqual((thrownError as MultiDisposeError).errors.length, 2); - assert.strictEqual((thrownError as MultiDisposeError).errors[0].message, 'I am error 1'); - assert.strictEqual((thrownError as MultiDisposeError).errors[1].message, 'I am error 2'); + assert.ok(thrownError instanceof AggregateError); + assert.strictEqual((thrownError as AggregateError).errors.length, 2); + assert.strictEqual((thrownError as AggregateError).errors[0].message, 'I am error 1'); + assert.strictEqual((thrownError as AggregateError).errors[1].message, 'I am error 2'); }); test('Action bar has broken accessibility #100273', function () { @@ -167,10 +167,10 @@ suite('DisposableStore', () => { assert.ok(disposedValues.has(1)); assert.ok(disposedValues.has(4)); - assert.ok(thrownError instanceof MultiDisposeError); - assert.strictEqual((thrownError as MultiDisposeError).errors.length, 2); - assert.strictEqual((thrownError as MultiDisposeError).errors[0].message, 'I am error 1'); - assert.strictEqual((thrownError as MultiDisposeError).errors[1].message, 'I am error 2'); + assert.ok(thrownError instanceof AggregateError); + assert.strictEqual((thrownError as AggregateError).errors.length, 2); + assert.strictEqual((thrownError as AggregateError).errors[0].message, 'I am error 1'); + assert.strictEqual((thrownError as AggregateError).errors[1].message, 'I am error 2'); }); }); diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index 3a979de3229..896d06ec812 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -852,12 +852,12 @@ suite('Map', () => { for (const item of keys) { tst.set(item, true); - assert.ok(tst._isBalanced()); + assert.ok(tst._isBalanced(), `SET${item}|${keys.map(String).join()}`); } for (const item of keys) { tst.delete(item); - assert.ok(tst._isBalanced()); + assert.ok(tst._isBalanced(), `DEL${item}|${keys.map(String).join()}`); } } }); diff --git a/src/vs/base/test/common/observable.test.ts b/src/vs/base/test/common/observable.test.ts index 8adba720180..a3460dca22b 100644 --- a/src/vs/base/test/common/observable.test.ts +++ b/src/vs/base/test/common/observable.test.ts @@ -5,8 +5,8 @@ import * as assert from 'assert'; import { Emitter } from 'vs/base/common/event'; -import { autorun, derived, IObserver, ITransaction, observableFromEvent, observableValue, transaction } from 'vs/base/common/observable'; -import { BaseObservable } from 'vs/base/common/observableImpl/base'; +import { ISettableObservable, autorun, derived, ITransaction, observableFromEvent, observableValue, transaction } from 'vs/base/common/observable'; +import { BaseObservable, IObservable, IObserver } from 'vs/base/common/observableImpl/base'; suite('observable integration', () => { test('basic observable + autorun', () => { @@ -209,29 +209,41 @@ suite('observable integration', () => { ]); }); - test('transaction from autorun', () => { + test('self-disposing autorun', () => { const log = new Log(); - const observable1 = observableValue('MyObservableValue1', 0); - const observable2 = observableValue('MyObservableValue2', 0); - - const computed = derived('computed', (reader) => { - const value1 = observable1.read(reader); - const value2 = observable2.read(reader); - const sum = value1 + value2; - log.log(`recompute: ${value1} + ${value2} = ${sum}`); - return sum; - }); - - autorun('autorun', (reader) => { - log.log(`value: ${computed.read(reader)}`); - transaction(tx => { - - }); + const observable1 = new LoggingObservableValue('MyObservableValue1', 0, log); + const observable2 = new LoggingObservableValue('MyObservableValue2', 0, log); + const observable3 = new LoggingObservableValue('MyObservableValue3', 0, log); + const d = autorun('autorun', (reader) => { + if (observable1.read(reader) >= 2) { + observable2.read(reader); + d.dispose(); + observable3.read(reader); + } }); + assert.deepStrictEqual(log.getAndClearEntries(), [ + 'MyObservableValue1.firstObserverAdded', + 'MyObservableValue1.get', + ]); + observable1.set(1, undefined); + assert.deepStrictEqual(log.getAndClearEntries(), [ + 'MyObservableValue1.set (value 1)', + 'MyObservableValue1.get', + ]); + observable1.set(2, undefined); + assert.deepStrictEqual(log.getAndClearEntries(), [ + 'MyObservableValue1.set (value 2)', + 'MyObservableValue1.get', + 'MyObservableValue2.firstObserverAdded', + 'MyObservableValue2.get', + 'MyObservableValue1.lastObserverRemoved', + 'MyObservableValue2.lastObserverRemoved', + 'MyObservableValue3.get', + ]); }); test('from event', () => { @@ -382,47 +394,8 @@ suite('observable details', () => { test('1', () => { const log = new Log(); - class TrackedObservableValue extends BaseObservable { - private value: T; - - constructor(initialValue: T) { - super(); - this.value = initialValue; - } - - readonly debugName = 'TrackedObservableValue'; - - public override addObserver(observer: IObserver): void { - log.log(`observable.addObserver ${observer.toString()}`); - super.addObserver(observer); - } - - public override removeObserver(observer: IObserver): void { - log.log(`observable.removeObserver ${observer.toString()}`); - super.removeObserver(observer); - } - - public get(): T { - log.log('observable.get'); - return this.value; - } - - public set(value: T, tx: ITransaction): void { - log.log(`observable.set (value ${value})`); - - if (this.value === value) { - return; - } - this.value = value; - for (const observer of this.observers) { - tx.updateObserver(observer, this); - observer.handleChange(this, undefined); - } - } - } - const shouldReadObservable = observableValue('shouldReadObservable', true); - const observable = new TrackedObservableValue(0); + const observable = new LoggingObservableValue('observable', 0, log); const computed = derived('test', reader => { if (shouldReadObservable.read(reader)) { return observable.read(reader) * 2; @@ -434,11 +407,7 @@ suite('observable details', () => { log.log(`autorun: ${value}`); }); - assert.deepStrictEqual(log.getAndClearEntries(), [ - 'observable.addObserver LazyDerived', - 'observable.get', - 'autorun: 0', - ]); + assert.deepStrictEqual(log.getAndClearEntries(), (["observable.firstObserverAdded", "observable.get", "autorun: 0"])); transaction(tx => { observable.set(1, tx); @@ -448,12 +417,82 @@ suite('observable details', () => { assert.deepStrictEqual(log.getAndClearEntries(), ([])); computed.get(); - assert.deepStrictEqual(log.getAndClearEntries(), (["observable.removeObserver LazyDerived"])); + assert.deepStrictEqual(log.getAndClearEntries(), (["observable.lastObserverRemoved"])); }); assert.deepStrictEqual(log.getAndClearEntries(), (["autorun: 1"])); }); }); +export class LoggingObserver implements IObserver { + private count = 0; + + constructor(public readonly debugName: string, private readonly log: Log) { + } + + beginUpdate(observable: IObservable): void { + this.count++; + this.log.log(`${this.debugName}.beginUpdate (count ${this.count})`); + } + handleChange(observable: IObservable, change: TChange): void { + this.log.log(`${this.debugName}.handleChange (count ${this.count})`); + } + endUpdate(observable: IObservable): void { + this.log.log(`${this.debugName}.endUpdate (count ${this.count})`); + this.count--; + } +} + +export class LoggingObservableValue + extends BaseObservable + implements ISettableObservable +{ + private value: T; + + constructor(public readonly debugName: string, initialValue: T, private readonly log: Log) { + super(); + this.value = initialValue; + } + + protected override onFirstObserverAdded(): void { + this.log.log(`${this.debugName}.firstObserverAdded`); + } + + protected override onLastObserverRemoved(): void { + this.log.log(`${this.debugName}.lastObserverRemoved`); + } + + public get(): T { + this.log.log(`${this.debugName}.get`); + return this.value; + } + + public set(value: T, tx: ITransaction | undefined, change: TChange): void { + if (this.value === value) { + return; + } + + if (!tx) { + transaction((tx) => { + this.set(value, tx, change); + }, () => `Setting ${this.debugName}`); + return; + } + + this.log.log(`${this.debugName}.set (value ${value})`); + + this.value = value; + + for (const observer of this.observers) { + tx.updateObserver(observer, this); + observer.handleChange(this, change); + } + } + + override toString(): string { + return `${this.debugName}: ${this.value}`; + } +} + class Log { private readonly entries: string[] = []; public log(message: string): void { diff --git a/src/vs/base/test/common/types.test.ts b/src/vs/base/test/common/types.test.ts index cb7dedbe272..1f5e7d0b812 100644 --- a/src/vs/base/test/common/types.test.ts +++ b/src/vs/base/test/common/types.test.ts @@ -82,24 +82,6 @@ suite('Types', () => { assert(types.isEmptyObject({})); }); - test('isArray', () => { - assert(!types.isArray(undefined)); - assert(!types.isArray(null)); - assert(!types.isArray('foo')); - assert(!types.isArray(5)); - assert(!types.isArray(true)); - assert(!types.isArray({})); - assert(!types.isArray(/test/)); - assert(!types.isArray(new RegExp(''))); - assert(!types.isArray(new Date())); - assert(!types.isArray(assert)); - assert(!types.isArray(function foo() { /**/ })); - assert(!types.isArray({ foo: 'bar' })); - - assert(types.isArray([])); - assert(types.isArray([1, 2, '3'])); - }); - test('isString', () => { assert(!types.isString(undefined)); assert(!types.isString(null)); diff --git a/src/vs/base/test/node/decoder.test.ts b/src/vs/base/test/node/decoder.test.ts deleted file mode 100644 index aa2e867c741..00000000000 --- a/src/vs/base/test/node/decoder.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import { LineDecoder } from 'vs/base/node/decoder'; - -suite('Decoder', () => { - - test('decoding', () => { - const lineDecoder = new LineDecoder(); - let res = lineDecoder.write(Buffer.from('hello')); - assert.strictEqual(res.length, 0); - - res = lineDecoder.write(Buffer.from('\nworld')); - assert.strictEqual(res[0], 'hello'); - assert.strictEqual(res.length, 1); - - assert.strictEqual(lineDecoder.end(), 'world'); - }); -}); diff --git a/src/vs/base/test/node/pfs/pfs.test.ts b/src/vs/base/test/node/pfs/pfs.test.ts index e45782e236f..b4661751c0c 100644 --- a/src/vs/base/test/node/pfs/pfs.test.ts +++ b/src/vs/base/test/node/pfs/pfs.test.ts @@ -11,9 +11,11 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { randomPath } from 'vs/base/common/extpath'; import { join, sep } from 'vs/base/common/path'; import { isWindows } from 'vs/base/common/platform'; -import { Promises, RimRafMode, rimrafSync, SymlinkSupport, writeFileSync } from 'vs/base/node/pfs'; +import { configureFlushOnWrite, Promises, RimRafMode, rimrafSync, SymlinkSupport, writeFileSync } from 'vs/base/node/pfs'; import { flakySuite, getPathFromAmdModule, getRandomTestPath } from 'vs/base/test/node/testUtils'; +configureFlushOnWrite(false); // speed up all unit tests by disabling flush on write + flakySuite('PFS', function () { let testDir: string; @@ -88,6 +90,16 @@ flakySuite('PFS', function () { assert.ok(!fs.existsSync(testDir)); }); + test('rimraf - path does not exist - move', async () => { + const nonExistingDir = join(testDir, 'unknown-move'); + await Promises.rm(nonExistingDir, RimRafMode.MOVE); + }); + + test('rimraf - path does not exist - unlink', async () => { + const nonExistingDir = join(testDir, 'unknown-unlink'); + await Promises.rm(nonExistingDir, RimRafMode.UNLINK); + }); + test('rimraf - recursive folder structure - unlink', async () => { fs.writeFileSync(join(testDir, 'somefile.txt'), 'Contents'); fs.writeFileSync(join(testDir, 'someOtherFile.txt'), 'Contents'); @@ -368,24 +380,36 @@ flakySuite('PFS', function () { const smallData = 'Hello World'; const bigData = (new Array(100 * 1024)).join('Large String\n'); - return testWriteFileAndFlush(smallData, smallData, bigData, bigData); + return testWriteFile(smallData, smallData, bigData, bigData); + }); + + test('writeFile (string) - flush on write', async () => { + configureFlushOnWrite(true); + try { + const smallData = 'Hello World'; + const bigData = (new Array(100 * 1024)).join('Large String\n'); + + return await testWriteFile(smallData, smallData, bigData, bigData); + } finally { + configureFlushOnWrite(false); + } }); test('writeFile (Buffer)', async () => { const smallData = 'Hello World'; const bigData = (new Array(100 * 1024)).join('Large String\n'); - return testWriteFileAndFlush(Buffer.from(smallData), smallData, Buffer.from(bigData), bigData); + return testWriteFile(Buffer.from(smallData), smallData, Buffer.from(bigData), bigData); }); test('writeFile (UInt8Array)', async () => { const smallData = 'Hello World'; const bigData = (new Array(100 * 1024)).join('Large String\n'); - return testWriteFileAndFlush(VSBuffer.fromString(smallData).buffer, smallData, VSBuffer.fromString(bigData).buffer, bigData); + return testWriteFile(VSBuffer.fromString(smallData).buffer, smallData, VSBuffer.fromString(bigData).buffer, bigData); }); - async function testWriteFileAndFlush( + async function testWriteFile( smallData: string | Buffer | Uint8Array, smallDataValue: string, bigData: string | Buffer | Uint8Array, diff --git a/src/vs/base/worker/workerMain.ts b/src/vs/base/worker/workerMain.ts index c7476dc341a..9b4656b31c4 100644 --- a/src/vs/base/worker/workerMain.ts +++ b/src/vs/base/worker/workerMain.ts @@ -17,7 +17,8 @@ // see https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor const fnArgs = args.slice(0, -1).join(','); const fnBody = args.pop()!.toString(); - const body = `(function anonymous(${fnArgs}) {\n${fnBody}\n})`; + // Do not add a new line to fnBody, as this will confuse source maps. + const body = `(function anonymous(${fnArgs}) { ${fnBody}\n})`; return body; } }) diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts index 221d77ffdfa..a49cc156f35 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts @@ -5,7 +5,7 @@ import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { IExtensionGalleryService, IExtensionIdentifier, IGlobalExtensionEnablementService, ServerDidUninstallExtensionEvent, ServerInstallExtensionResult, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionIdentifier, IGlobalExtensionEnablementService, DidUninstallExtensionEvent, InstallExtensionResult, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { getIdAndVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; @@ -34,12 +34,11 @@ export class ExtensionsCleaner extends Disposable { ) { super(); - extensionManagementService.removeUninstalledExtensions(this.userDataProfilesService.profiles.length === 0); + extensionManagementService.removeUninstalledExtensions(this.userDataProfilesService.profiles.length === 1); migrateUnsupportedExtensions(extensionManagementService, extensionGalleryService, extensionStorageService, extensionEnablementService, logService); ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService); this._register(instantiationService.createInstance(ProfileExtensionsCleaner)); } - } class ProfileExtensionsCleaner extends Disposable { @@ -59,14 +58,14 @@ class ProfileExtensionsCleaner extends Disposable { this.onDidChangeProfiles({ added: this.userDataProfilesService.profiles, removed: [], all: this.userDataProfilesService.profiles }); } - private async onDidChangeProfiles({ added, removed, all }: DidChangeProfilesEvent): Promise { + private async onDidChangeProfiles({ added, removed, all }: Omit): Promise { try { await Promise.all(removed.map(profile => profile.extensionsResource ? this.removeExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); } catch (error) { this.logService.error(error); } - if (all.length === 0) { + if (all.length === 1) { // Exit profile mode this.profileModeDisposables.clear(); // Listen for entering into profile mode @@ -103,7 +102,7 @@ class ProfileExtensionsCleaner extends Disposable { } } - private async onDidInstallExtensions(installedExtensions: readonly ServerInstallExtensionResult[]): Promise { + private async onDidInstallExtensions(installedExtensions: readonly InstallExtensionResult[]): Promise { for (const { local, profileLocation } of installedExtensions) { if (!local || !profileLocation) { continue; @@ -112,7 +111,7 @@ class ProfileExtensionsCleaner extends Disposable { } } - private async onDidUninstallExtension(e: ServerDidUninstallExtensionEvent): Promise { + private async onDidUninstallExtension(e: DidUninstallExtensionEvent): Promise { if (!e.profileLocation || !e.version) { return; } @@ -184,5 +183,4 @@ class ProfileExtensionsCleaner extends Disposable { const [id, version] = getIdAndVersion(key); return version ? { identifier: { id }, version } : undefined; } - } diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts index 56eb3683002..1f55a52057a 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts @@ -8,22 +8,21 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { Disposable } from 'vs/base/common/lifecycle'; import { join } from 'vs/base/common/path'; import { Promises } from 'vs/base/node/pfs'; -import { IBackupWorkspacesFormat } from 'vs/platform/backup/node/backup'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { ILogService } from 'vs/platform/log/common/log'; +import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; +import { StorageClient } from 'vs/platform/storage/common/storageIpc'; +import { EXTENSION_DEVELOPMENT_EMPTY_WINDOW_WORKSPACE } from 'vs/platform/workspace/common/workspace'; +import { NON_EMPTY_WORKSPACE_ID_LENGTH } from 'vs/platform/workspaces/node/workspaces'; -export class StorageDataCleaner extends Disposable { - - // Workspace/Folder storage names are MD5 hashes (128bits / 4 due to hex presentation) - private static readonly NON_EMPTY_WORKSPACE_ID_LENGTH = 128 / 4; - - // Reserved empty window workspace storage name when in extension development - private static readonly EXTENSION_DEV_EMPTY_WINDOW_ID = 'ext-dev'; +export class UnusedWorkspaceStorageDataCleaner extends Disposable { constructor( - private readonly backupWorkspacesPath: string, @INativeEnvironmentService private readonly environmentService: INativeEnvironmentService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @INativeHostService private readonly nativeHostService: INativeHostService, + @IMainProcessService private readonly mainProcessService: IMainProcessService ) { super(); @@ -34,31 +33,36 @@ export class StorageDataCleaner extends Disposable { } private async cleanUpStorage(): Promise { - this.logService.trace('[storage cleanup]: Starting to clean up storage folders.'); + this.logService.trace('[storage cleanup]: Starting to clean up workspace storage folders for unused empty workspaces.'); try { - - // Leverage the backup workspace file to find out which empty workspace is currently in use to - // determine which empty workspace storage can safely be deleted - const contents = await Promises.readFile(this.backupWorkspacesPath, 'utf8'); - - const workspaces = JSON.parse(contents) as IBackupWorkspacesFormat; - const emptyWorkspaces = workspaces.emptyWorkspaceInfos.map(emptyWorkspace => emptyWorkspace.backupFolder); - - // Read all workspace storage folders that exist & cleanup unused const workspaceStorageFolders = await Promises.readdir(this.environmentService.workspaceStorageHome.fsPath); + const storageClient = new StorageClient(this.mainProcessService.getChannel('storage')); + await Promise.all(workspaceStorageFolders.map(async workspaceStorageFolder => { - if ( - workspaceStorageFolder.length === StorageDataCleaner.NON_EMPTY_WORKSPACE_ID_LENGTH || // keep non-empty workspaces - workspaceStorageFolder === StorageDataCleaner.EXTENSION_DEV_EMPTY_WINDOW_ID || // keep empty extension dev workspaces - emptyWorkspaces.indexOf(workspaceStorageFolder) >= 0 // keep empty workspaces that are in use - ) { - return; + const workspaceStoragePath = join(this.environmentService.workspaceStorageHome.fsPath, workspaceStorageFolder); + + if (workspaceStorageFolder.length === NON_EMPTY_WORKSPACE_ID_LENGTH) { + return; // keep workspace storage for folders/workspaces that can be accessed still } - this.logService.trace(`[storage cleanup]: Deleting workspace storage folder ${workspaceStorageFolder}.`); + if (workspaceStorageFolder === EXTENSION_DEVELOPMENT_EMPTY_WINDOW_WORKSPACE.id) { + return; // keep workspace storage for empty extension development workspaces + } - await Promises.rm(join(this.environmentService.workspaceStorageHome.fsPath, workspaceStorageFolder)); + const windows = await this.nativeHostService.getWindows(); + if (windows.some(window => window.workspace?.id === workspaceStorageFolder)) { + return; // keep workspace storage for empty workspaces opened as window + } + + const isStorageUsed = await storageClient.isUsed(workspaceStoragePath); + if (isStorageUsed) { + return; // keep workspace storage for empty workspaces that are in use + } + + this.logService.trace(`[storage cleanup]: Deleting workspace storage folder ${workspaceStorageFolder} as it seems to be an unused empty workspace.`); + + await Promises.rm(workspaceStoragePath); })); } catch (error) { onUnexpectedError(error); diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/userDataProfilesCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/userDataProfilesCleaner.ts new file mode 100644 index 00000000000..37c57771e24 --- /dev/null +++ b/src/vs/code/electron-browser/sharedProcess/contrib/userDataProfilesCleaner.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 { RunOnceScheduler } from 'vs/base/common/async'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; + +export class UserDataProfilesCleaner extends Disposable { + + constructor( + @IUserDataProfilesService userDataProfilesService: IUserDataProfilesService + ) { + super(); + + const scheduler = this._register(new RunOnceScheduler(() => { + userDataProfilesService.cleanUp(); + }, 10 * 1000 /* after 10s */)); + scheduler.schedule(); + } +} diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js index c9651466d39..1383bc8331e 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js @@ -7,12 +7,8 @@ (function () { 'use strict'; - const bootstrap = bootstrapLib(); const bootstrapWindow = bootstrapWindowLib(); - // Avoid Monkey Patches from Application Insights - bootstrap.avoidMonkeyPatchFromAppInsights(); - // Load shared process into window bootstrapWindow.load(['vs/code/electron-browser/sharedProcess/sharedProcessMain'], function (sharedProcess, configuration) { return sharedProcess.main(configuration); @@ -26,14 +22,6 @@ } ); - /** - * @returns {{ avoidMonkeyPatchFromAppInsights: () => void; }} - */ - function bootstrapLib() { - // @ts-ignore (defined in bootstrap.js) - return window.MonacoBootstrap; - } - /** * @typedef {import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration} ISandboxConfiguration * diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 11116cc4cce..375339be219 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -18,7 +18,7 @@ import { ExtensionsCleaner } from 'vs/code/electron-browser/sharedProcess/contri import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner'; import { LocalizationsUpdater } from 'vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater'; import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; -import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner'; +import { UnusedWorkspaceStorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner'; import { IChecksumService } from 'vs/platform/checksum/common/checksumService'; import { ChecksumService } from 'vs/platform/checksum/node/checksumService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -53,7 +53,6 @@ import { FollowerLogService, LoggerChannelClient, LogLevelChannelClient } from ' import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; -import { RequestService } from 'vs/platform/request/browser/requestService'; import { IRequestService } from 'vs/platform/request/common/request'; import { ISharedProcessConfiguration } from 'vs/platform/sharedProcess/node/sharedProcess'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -63,8 +62,7 @@ import { ICustomEndpointTelemetryService, ITelemetryService } from 'vs/platform/ import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc'; import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { supportsTelemetry, ITelemetryAppender, NullAppender, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils'; -import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; +import { supportsTelemetry, ITelemetryAppender, NullAppender, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { CustomEndpointTelemetryService } from 'vs/platform/telemetry/node/customEndpointTelemetryService'; import { LocalReconnectConstants, TerminalIpcChannels, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal'; @@ -105,7 +103,9 @@ import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } fro import { PolicyChannelClient } from 'vs/platform/policy/common/policyIpc'; import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy'; import { UserDataProfilesNativeService } from 'vs/platform/userDataProfile/electron-sandbox/userDataProfile'; -import { OneDataSystemWebAppender } from 'vs/platform/telemetry/browser/1dsAppender'; +import { SharedProcessRequestService } from 'vs/platform/request/electron-browser/sharedProcessRequestService'; +import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; +import { UserDataProfilesCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/userDataProfilesCleaner'; class SharedProcessMain extends Disposable { @@ -133,7 +133,7 @@ class SharedProcessMain extends Disposable { // application is shutting down anyways. // const eventName = 'vscode:electron-main->shared-process=disposeWorker'; - const onDisposeWorker = (event: unknown, configuration: ISharedProcessWorkerConfiguration) => this.onDisposeWorker(configuration); + const onDisposeWorker = (event: unknown, configuration: ISharedProcessWorkerConfiguration) => { this.onDisposeWorker(configuration); }; ipcRenderer.on(eventName, onDisposeWorker); this._register(toDisposable(() => ipcRenderer.removeListener(eventName, onDisposeWorker))); } @@ -167,10 +167,11 @@ class SharedProcessMain extends Disposable { this._register(combinedDisposable( instantiationService.createInstance(CodeCacheCleaner, this.configuration.codeCachePath), instantiationService.createInstance(LanguagePackCachedDataCleaner), - instantiationService.createInstance(StorageDataCleaner, this.configuration.backupWorkspacesPath), + instantiationService.createInstance(UnusedWorkspaceStorageDataCleaner), instantiationService.createInstance(LogsDataCleaner), instantiationService.createInstance(LocalizationsUpdater), - instantiationService.createInstance(ExtensionsCleaner) + instantiationService.createInstance(ExtensionsCleaner), + instantiationService.createInstance(UserDataProfilesCleaner) )); } @@ -232,7 +233,7 @@ class SharedProcessMain extends Disposable { fileService.registerProvider(Schemas.vscodeUserData, userDataFileSystemProvider); // User Data Profiles - const userDataProfilesService = this._register(new UserDataProfilesNativeService(this.configuration.profiles, mainProcessService, environmentService, fileService, logService)); + const userDataProfilesService = this._register(new UserDataProfilesNativeService(this.configuration.profiles, mainProcessService, environmentService)); services.set(IUserDataProfilesService, userDataProfilesService); // Configuration @@ -254,20 +255,20 @@ class SharedProcessMain extends Disposable { services.set(IUriIdentityService, new UriIdentityService(fileService)); // Request - services.set(IRequestService, new SyncDescriptor(RequestService)); + services.set(IRequestService, new SharedProcessRequestService(mainProcessService, configurationService, logService)); // Checksum - services.set(IChecksumService, new SyncDescriptor(ChecksumService)); + services.set(IChecksumService, new SyncDescriptor(ChecksumService, undefined, false /* proxied to other processes */)); // V8 Inspect profiler - services.set(IV8InspectProfilingService, new SyncDescriptor(V8InspectProfilingService)); + services.set(IV8InspectProfilingService, new SyncDescriptor(V8InspectProfilingService, undefined, false /* proxied to other processes */)); // Native Host const nativeHostService = ProxyChannel.toService(mainProcessService.getChannel('nativeHost'), { context: this.configuration.windowId }); services.set(INativeHostService, nativeHostService); // Download - services.set(IDownloadService, new SyncDescriptor(DownloadService)); + services.set(IDownloadService, new SyncDescriptor(DownloadService, undefined, true)); // Extension recommendations const activeWindowManager = this._register(new ActiveWindowManager(nativeHostService)); @@ -277,25 +278,20 @@ class SharedProcessMain extends Disposable { // Telemetry let telemetryService: ITelemetryService; const appenders: ITelemetryAppender[] = []; + const internalTelemetry = isInternalTelemetry(productService, configurationService); if (supportsTelemetry(productService, environmentService)) { const logAppender = new TelemetryLogAppender(loggerService, environmentService); appenders.push(logAppender); const { installSourcePath } = environmentService; - const internalTesting = configurationService.getValue('telemetry.internalTesting'); - if (internalTesting && productService.aiConfig?.ariaKey) { - const collectorAppender = new OneDataSystemWebAppender('monacoworkbench', null, productService.aiConfig.ariaKey); + if (productService.aiConfig?.ariaKey) { + const collectorAppender = new OneDataSystemAppender(internalTelemetry, 'monacoworkbench', null, productService.aiConfig.ariaKey); this._register(toDisposable(() => collectorAppender.flush())); // Ensure the 1DS appender is disposed so that it flushes remaining data appenders.push(collectorAppender); - } else if (productService.aiConfig && productService.aiConfig.asimovKey) { - // Application Insights - const appInsightsAppender = new AppInsightsAppender('monacoworkbench', null, productService.aiConfig.asimovKey); - this._register(toDisposable(() => appInsightsAppender.flush())); // Ensure the AI appender is disposed so that it flushes remaining data - appenders.push(appInsightsAppender); } telemetryService = new TelemetryService({ appenders, - commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, productService.msftInternalDomains, installSourcePath), + commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, internalTelemetry, installSourcePath), sendErrorTelemetry: true, piiPaths: getPiiPathsFromEnvironment(environmentService), }, configurationService, productService); @@ -313,35 +309,35 @@ class SharedProcessMain extends Disposable { services.set(ICustomEndpointTelemetryService, customEndpointTelemetryService); // Extension Management - services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService)); - services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService)); - services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService, undefined, true)); + services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService, undefined, true)); + services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService, undefined, true)); // Extension Gallery - services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); + services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService, undefined, true)); // Extension Tips - services.set(IExtensionTipsService, new SyncDescriptor(ExtensionTipsService)); + services.set(IExtensionTipsService, new SyncDescriptor(ExtensionTipsService, undefined, false /* Eagerly scans and computes exe based recommendations */)); // Localizations - services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService)); + services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService, undefined, false /* proxied to other processes */)); // Diagnostics - services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); + services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, undefined, false /* proxied to other processes */)); // Settings Sync - services.set(IUserDataSyncAccountService, new SyncDescriptor(UserDataSyncAccountService)); - services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService)); + services.set(IUserDataSyncAccountService, new SyncDescriptor(UserDataSyncAccountService, undefined, true)); + services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService, undefined, true)); services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(this.server.getChannel('userDataSyncUtil', client => client.ctx !== 'main'))); - services.set(IGlobalExtensionEnablementService, new SyncDescriptor(GlobalExtensionEnablementService)); - services.set(IIgnoredExtensionsManagementService, new SyncDescriptor(IgnoredExtensionsManagementService)); + services.set(IGlobalExtensionEnablementService, new SyncDescriptor(GlobalExtensionEnablementService, undefined, false /* Eagerly resets installed extensions */)); + services.set(IIgnoredExtensionsManagementService, new SyncDescriptor(IgnoredExtensionsManagementService, undefined, true)); services.set(IExtensionStorageService, new SyncDescriptor(ExtensionStorageService)); - services.set(IUserDataSyncStoreManagementService, new SyncDescriptor(UserDataSyncStoreManagementService)); - services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService)); - services.set(IUserDataSyncMachinesService, new SyncDescriptor(UserDataSyncMachinesService)); - services.set(IUserDataSyncBackupStoreService, new SyncDescriptor(UserDataSyncBackupStoreService)); - services.set(IUserDataSyncEnablementService, new SyncDescriptor(UserDataSyncEnablementService)); - services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService)); + services.set(IUserDataSyncStoreManagementService, new SyncDescriptor(UserDataSyncStoreManagementService, undefined, true)); + services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService, undefined, true)); + services.set(IUserDataSyncMachinesService, new SyncDescriptor(UserDataSyncMachinesService, undefined, true)); + services.set(IUserDataSyncBackupStoreService, new SyncDescriptor(UserDataSyncBackupStoreService, undefined, false /* Eagerly cleans up old backups */)); + services.set(IUserDataSyncEnablementService, new SyncDescriptor(UserDataSyncEnablementService, undefined, true)); + services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService, undefined, false /* Initializes the Sync State */)); const ptyHostService = new PtyHostService({ graceTime: LocalReconnectConstants.GraceTime, @@ -358,7 +354,7 @@ class SharedProcessMain extends Disposable { services.set(ILocalPtyService, this._register(ptyHostService)); // Signing - services.set(ISignService, new SyncDescriptor(SignService)); + services.set(ISignService, new SyncDescriptor(SignService, undefined, false /* proxied to other processes */)); // Tunnel services.set(ISharedTunnelsService, new SyncDescriptor(SharedTunnelsService)); @@ -426,6 +422,7 @@ class SharedProcessMain extends Disposable { // Worker const sharedProcessWorkerChannel = ProxyChannel.fromService(accessor.get(ISharedProcessWorkerService)); this.server.registerChannel(ipcSharedProcessWorkerChannelName, sharedProcessWorkerChannel); + } private registerErrorHandler(logService: ILogService): void { diff --git a/src/vs/code/electron-browser/workbench/workbench.html b/src/vs/code/electron-browser/workbench/workbench.html deleted file mode 100644 index 47066f520be..00000000000 --- a/src/vs/code/electron-browser/workbench/workbench.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js deleted file mode 100644 index 7ceef489fcc..00000000000 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ /dev/null @@ -1,213 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/// - -//@ts-check -(function () { - 'use strict'; - - const bootstrapWindow = bootstrapWindowLib(); - - // Add a perf entry right from the top - performance.mark('code/didStartRenderer'); - - // Load workbench main JS, CSS and NLS all in parallel. This is an - // optimization to prevent a waterfall of loading to happen, because - // we know for a fact that workbench.desktop.main will depend on - // the related CSS and NLS counterparts. - bootstrapWindow.load([ - 'vs/workbench/workbench.desktop.main', - 'vs/nls!vs/workbench/workbench.desktop.main', - 'vs/css!vs/workbench/workbench.desktop.main' - ], - function (_, configuration) { - - // Mark start of workbench - performance.mark('code/didLoadWorkbenchMain'); - - // @ts-ignore - return require('vs/workbench/electron-sandbox/desktop.main').main(configuration); - }, - { - configureDeveloperSettings: function (windowConfig) { - return { - // disable automated devtools opening on error when running extension tests - // as this can lead to nondeterministic test execution (devtools steals focus) - forceDisableShowDevtoolsOnError: typeof windowConfig.extensionTestsPath === 'string', - // enable devtools keybindings in extension development window - forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath) && windowConfig.extensionDevelopmentPath.length > 0, - removeDeveloperKeybindingsAfterLoad: true - }; - }, - canModifyDOM: function (windowConfig) { - showSplash(windowConfig); - }, - beforeLoaderConfig: function (loaderConfig) { - loaderConfig.recordStats = true; - }, - beforeRequire: function () { - performance.mark('code/willLoadWorkbenchMain'); - - // It looks like browsers only lazily enable - // the element when needed. Since we - // leverage canvas elements in our code in many - // locations, we try to help the browser to - // initialize canvas when it is idle, right - // before we wait for the scripts to be loaded. - // @ts-ignore - window.requestIdleCallback(() => { - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - context.clearRect(0, 0, canvas.width, canvas.height); - canvas.remove(); - }, { timeout: 50 }); - } - } - ); - - //#region Helpers - - /** - * @typedef {import('../../../platform/window/common/window').INativeWindowConfiguration} INativeWindowConfiguration - * @typedef {import('../../../platform/environment/common/argv').NativeParsedArgs} NativeParsedArgs - * - * @returns {{ - * load: ( - * modules: string[], - * resultCallback: (result, configuration: INativeWindowConfiguration & NativeParsedArgs) => unknown, - * options?: { - * configureDeveloperSettings?: (config: INativeWindowConfiguration & NativeParsedArgs) => { - * forceDisableShowDevtoolsOnError?: boolean, - * forceEnableDeveloperKeybindings?: boolean, - * disallowReloadKeybinding?: boolean, - * removeDeveloperKeybindingsAfterLoad?: boolean - * }, - * canModifyDOM?: (config: INativeWindowConfiguration & NativeParsedArgs) => void, - * beforeLoaderConfig?: (loaderConfig: object) => void, - * beforeRequire?: () => void - * } - * ) => Promise - * }} - */ - function bootstrapWindowLib() { - // @ts-ignore (defined in bootstrap-window.js) - return window.MonacoBootstrapWindow; - } - - /** - * @param {INativeWindowConfiguration & NativeParsedArgs} configuration - */ - function showSplash(configuration) { - performance.mark('code/willShowPartsSplash'); - - let data = configuration.partsSplash; - - if (data) { - // high contrast mode has been turned by the OS -> ignore stored colors and layouts - if (configuration.autoDetectHighContrast && configuration.colorScheme.highContrast) { - if ((configuration.colorScheme.dark && data.baseTheme !== 'hc-black') || (!configuration.colorScheme.dark && data.baseTheme !== 'hc-light')) { - data = undefined; - } - } else if (configuration.autoDetectColorScheme) { - // OS color scheme is tracked and has changed - if ((configuration.colorScheme.dark && data.baseTheme !== 'vs-dark') || (!configuration.colorScheme.dark && data.baseTheme !== 'vs')) { - data = undefined; - } - } - } - - // developing an extension -> ignore stored layouts - if (data && configuration.extensionDevelopmentPath) { - data.layoutInfo = undefined; - } - - // minimal color configuration (works with or without persisted data) - let baseTheme, shellBackground, shellForeground; - if (data) { - baseTheme = data.baseTheme; - shellBackground = data.colorInfo.editorBackground; - shellForeground = data.colorInfo.foreground; - } else if (configuration.autoDetectHighContrast && configuration.colorScheme.highContrast) { - if (configuration.colorScheme.dark) { - baseTheme = 'hc-black'; - shellBackground = '#000000'; - shellForeground = '#FFFFFF'; - } else { - baseTheme = 'hc-light'; - shellBackground = '#FFFFFF'; - shellForeground = '#000000'; - } - } else if (configuration.autoDetectColorScheme) { - if (configuration.colorScheme.dark) { - baseTheme = 'vs-dark'; - shellBackground = '#1E1E1E'; - shellForeground = '#CCCCCC'; - } else { - baseTheme = 'vs'; - shellBackground = '#FFFFFF'; - shellForeground = '#000000'; - } - } - - const style = document.createElement('style'); - style.className = 'initialShellColors'; - document.head.appendChild(style); - style.textContent = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`; - - // restore parts if possible (we might not always store layout info) - if (data?.layoutInfo) { - const { layoutInfo, colorInfo } = data; - - const splash = document.createElement('div'); - splash.id = 'monaco-parts-splash'; - splash.className = baseTheme; - - 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)); - - // part: title - const titleDiv = document.createElement('div'); - titleDiv.setAttribute('style', `position: absolute; width: 100%; left: 0; top: 0; height: ${layoutInfo.titleBarHeight}px; background-color: ${colorInfo.titleBarBackground}; -webkit-app-region: drag;`); - splash.appendChild(titleDiv); - - // part: activity bar - const activityDiv = document.createElement('div'); - activityDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: 0; width: ${layoutInfo.activityBarWidth}px; background-color: ${colorInfo.activityBarBackground};`); - splash.appendChild(activityDiv); - - // part: side bar (only when opening workspace/folder) - // folder or workspace -> status bar color, sidebar - if (configuration.workspace) { - const sideDiv = document.createElement('div'); - sideDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; width: ${layoutInfo.sideBarWidth}px; background-color: ${colorInfo.sideBarBackground};`); - splash.appendChild(sideDiv); - } - - // part: statusbar - const statusDiv = document.createElement('div'); - statusDiv.setAttribute('style', `position: absolute; width: 100%; bottom: 0; left: 0; height: ${layoutInfo.statusBarHeight}px; background-color: ${configuration.workspace ? colorInfo.statusBarBackground : colorInfo.statusBarNoFolderBackground};`); - splash.appendChild(statusDiv); - - document.body.appendChild(splash); - } - - performance.mark('code/didShowPartsSplash'); - } - - //#endregion -}()); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 7b912a581c3..6e807f2bb97 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -75,7 +75,7 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProp import { ITelemetryService, machineIdKey, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc'; import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { getPiiPathsFromEnvironment, getTelemetryLevel, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; +import { getPiiPathsFromEnvironment, getTelemetryLevel, isInternalTelemetry, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IUpdateService } from 'vs/platform/update/common/update'; import { UpdateChannel } from 'vs/platform/update/common/updateIpc'; import { DarwinUpdateService } from 'vs/platform/update/electron-main/updateService.darwin'; @@ -102,6 +102,15 @@ import { CredentialsNativeMainService } from 'vs/platform/credentials/electron-m import { IPolicyService } from 'vs/platform/policy/common/policy'; import { PolicyChannel } from 'vs/platform/policy/common/policyIpc'; import { IUserDataProfilesMainService } from 'vs/platform/userDataProfile/electron-main/userDataProfile'; +import { DefaultExtensionsProfileInitHandler } from 'vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit'; +import { RequestChannel } from 'vs/platform/request/common/requestIpc'; +import { IRequestService } from 'vs/platform/request/common/request'; +import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; +import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService'; +import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService'; +import { UserDataTransientProfilesHandler } from 'vs/platform/userDataProfile/electron-main/userDataTransientProfilesHandler'; +import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; +import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; /** * The main VS Code application. There will only ever be one instance, @@ -122,7 +131,8 @@ export class CodeApplication extends Disposable { @IConfigurationService private readonly configurationService: IConfigurationService, @IStateMainService private readonly stateMainService: IStateMainService, @IFileService private readonly fileService: IFileService, - @IProductService private readonly productService: IProductService + @IProductService private readonly productService: IProductService, + @IUserDataProfilesMainService private readonly userDataProfilesMainService: IUserDataProfilesMainService, ) { super(); @@ -525,14 +535,18 @@ export class CodeApplication extends Disposable { // Services const appInstantiationService = await this.initServices(machineId, sharedProcess, sharedProcessReady); - // Setup Auth Handler - this._register(appInstantiationService.createInstance(ProxyAuthHandler)); + // Setup Handlers + this.setUpHandlers(appInstantiationService); + + // Ensure profile exists when passed in from CLI + const profilePromise = this.userDataProfilesMainService.checkAndCreateProfileFromCli(this.environmentMainService.args); + const profile = profilePromise ? await profilePromise : undefined; // Init Channels appInstantiationService.invokeFunction(accessor => this.initChannels(accessor, mainProcessElectronServer, sharedProcessClient)); // Open Windows - const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, mainProcessElectronServer)); + const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, profile, mainProcessElectronServer)); // Post Open Windows Tasks appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor, sharedProcess)); @@ -541,6 +555,24 @@ export class CodeApplication extends Disposable { if (this.environmentMainService.args.trace) { appInstantiationService.invokeFunction(accessor => this.stopTracingEventually(accessor, windows)); } + + // Set lifecycle phase to `Eventually` after a short delay and when idle (min 2.5sec, max 5sec) + const eventuallyPhaseScheduler = this._register(new RunOnceScheduler(() => { + this._register(runWhenIdle(() => this.lifecycleMainService.phase = LifecycleMainPhase.Eventually, 2500)); + }, 2500)); + eventuallyPhaseScheduler.schedule(); + } + + private setUpHandlers(instantiationService: IInstantiationService): void { + + // Auth Handler + this._register(instantiationService.createInstance(ProxyAuthHandler)); + + // Default Extensions Profile Init Handler + this._register(instantiationService.createInstance(DefaultExtensionsProfileInitHandler)); + + // Transient profiles handler + this._register(instantiationService.createInstance(UserDataTransientProfilesHandler)); } private async resolveMachineId(): Promise { @@ -602,16 +634,16 @@ export class CodeApplication extends Disposable { } // Windows - services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, this.userEnv])); + services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, this.userEnv], false)); // Dialogs - services.set(IDialogMainService, new SyncDescriptor(DialogMainService)); + services.set(IDialogMainService, new SyncDescriptor(DialogMainService, undefined, true)); // Launch - services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService)); + services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService, undefined, false /* proxied to other processes */)); // Diagnostics - services.set(IDiagnosticsMainService, new SyncDescriptor(DiagnosticsMainService)); + services.set(IDiagnosticsMainService, new SyncDescriptor(DiagnosticsMainService, undefined, false /* proxied to other processes */)); services.set(IDiagnosticsService, ProxyChannel.toService(getDelayedChannel(sharedProcessReady.then(client => client.getChannel('diagnostics'))))); // Issues @@ -624,7 +656,7 @@ export class CodeApplication extends Disposable { services.set(IKeyboardLayoutMainService, new SyncDescriptor(KeyboardLayoutMainService)); // Native Host - services.set(INativeHostMainService, new SyncDescriptor(NativeHostMainService, [sharedProcess])); + services.set(INativeHostMainService, new SyncDescriptor(NativeHostMainService, [sharedProcess], false /* proxied to other processes */)); // Credentials services.set(ICredentialsMainService, new SyncDescriptor(CredentialsNativeMainService)); @@ -633,9 +665,9 @@ export class CodeApplication extends Disposable { services.set(IWebviewManagerService, new SyncDescriptor(WebviewMainService)); // Workspaces - services.set(IWorkspacesService, new SyncDescriptor(WorkspacesMainService)); - services.set(IWorkspacesManagementMainService, new SyncDescriptor(WorkspacesManagementMainService)); - services.set(IWorkspacesHistoryMainService, new SyncDescriptor(WorkspacesHistoryMainService)); + services.set(IWorkspacesService, new SyncDescriptor(WorkspacesMainService, undefined, false /* proxied to other processes */)); + services.set(IWorkspacesManagementMainService, new SyncDescriptor(WorkspacesManagementMainService, undefined, true)); + services.set(IWorkspacesHistoryMainService, new SyncDescriptor(WorkspacesHistoryMainService, undefined, false)); // Menubar services.set(IMenubarMainService, new SyncDescriptor(MenubarMainService)); @@ -660,25 +692,30 @@ export class CodeApplication extends Disposable { } // Backups - const backupMainService = new BackupMainService(this.environmentMainService, this.configurationService, this.logService); + const backupMainService = new BackupMainService(this.environmentMainService, this.configurationService, this.logService, this.lifecycleMainService); services.set(IBackupMainService, backupMainService); // URL handling - services.set(IURLService, new SyncDescriptor(NativeURLService)); + services.set(IURLService, new SyncDescriptor(NativeURLService, undefined, false /* proxied to other processes */)); // Telemetry if (supportsTelemetry(this.productService, this.environmentMainService)) { + const isInternal = isInternalTelemetry(this.productService, this.configurationService); const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender'))); const appender = new TelemetryAppenderClient(channel); - const commonProperties = resolveCommonProperties(this.fileService, release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, this.productService.msftInternalDomains, this.environmentMainService.installSourcePath); + const commonProperties = resolveCommonProperties(this.fileService, release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, isInternal, this.environmentMainService.installSourcePath); const piiPaths = getPiiPathsFromEnvironment(this.environmentMainService); const config: ITelemetryServiceConfig = { appenders: [appender], commonProperties, piiPaths, sendErrorTelemetry: true }; - services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); + services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config], false)); } else { services.set(ITelemetryService, NullTelemetryService); } + // Default Extensions Profile Init + services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService, undefined, true)); + services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService, undefined, true)); + // Init services that require it await backupMainService.initialize(); @@ -715,6 +752,10 @@ export class CodeApplication extends Disposable { mainProcessElectronServer.registerChannel('userDataProfiles', userDataProfilesService); sharedProcessClient.then(client => client.registerChannel('userDataProfiles', userDataProfilesService)); + // Request + const requestService = new RequestChannel(accessor.get(IRequestService)); + sharedProcessClient.then(client => client.registerChannel('request', requestService)); + // Update const updateChannel = new UpdateChannel(accessor.get(IUpdateService)); mainProcessElectronServer.registerChannel('update', updateChannel); @@ -785,7 +826,7 @@ export class CodeApplication extends Disposable { sharedProcessClient.then(client => client.registerChannel('logger', loggerChannel)); // Extension Host Debug Broadcasting - const electronExtensionHostDebugBroadcastChannel = new ElectronExtensionHostDebugBroadcastChannel(accessor.get(IWindowsMainService)); + const electronExtensionHostDebugBroadcastChannel = new ElectronExtensionHostDebugBroadcastChannel(accessor.get(IWindowsMainService), accessor.get(IUserDataProfilesMainService)); mainProcessElectronServer.registerChannel('extensionhostdebugservice', electronExtensionHostDebugBroadcastChannel); // Extension Host Starter @@ -793,7 +834,7 @@ export class CodeApplication extends Disposable { mainProcessElectronServer.registerChannel(ipcExtensionHostStarterChannelName, extensionHostStarterChannel); } - private openFirstWindow(accessor: ServicesAccessor, mainProcessElectronServer: ElectronIPCServer): ICodeWindow[] { + private openFirstWindow(accessor: ServicesAccessor, profile: IUserDataProfile | undefined, mainProcessElectronServer: ElectronIPCServer): ICodeWindow[] { const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); const urlService = accessor.get(IURLService); const nativeHostMainService = accessor.get(INativeHostMainService); @@ -877,13 +918,6 @@ export class CodeApplication extends Disposable { // or if no window is open (macOS only) shouldOpenInNewWindow ||= isMacintosh && windowsMainService.getWindowCount() === 0; - // Pass along edit session id - if (params.get('editSessionId') !== null) { - environmentService.editSessionId = params.get('editSessionId') ?? undefined; - params.delete('editSessionId'); - uri = uri.with({ query: params.toString() }); - } - // Check for URIs to open in window const windowOpenableFromProtocolLink = app.getWindowOpenableFromProtocolLink(uri); logService.trace('app#handleURL: windowOpenableFromProtocolLink = ', windowOpenableFromProtocolLink); @@ -960,31 +994,36 @@ export class CodeApplication extends Disposable { }); } - // new window if "-n" - if (args['new-window'] && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { - return windowsMainService.open({ - context, - cli: args, - forceNewWindow: true, - forceEmpty: true, - noRecentEntry, - waitMarkerFileURI, - initialStartup: true, - remoteAuthority - }); - } + // Start without file/folder arguments + if (!hasCliArgs && !hasFolderURIs && !hasFileURIs) { - // mac: open-file event received on startup - if (macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { - return windowsMainService.open({ - context: OpenContext.DOCK, - cli: args, - urisToOpen: macOpenFiles.map(file => this.getWindowOpenableFromPathSync(file)), - noRecentEntry, - waitMarkerFileURI, - initialStartup: true, - // remoteAuthority: will be determined based on macOpenFiles - }); + // Force new window + if (args['new-window'] || profile) { + return windowsMainService.open({ + context, + cli: args, + forceNewWindow: true, + forceEmpty: true, + noRecentEntry, + waitMarkerFileURI, + initialStartup: true, + remoteAuthority, + profile + }); + } + + // mac: open-file event received on startup + if (macOpenFiles.length) { + return windowsMainService.open({ + context: OpenContext.DOCK, + cli: args, + urisToOpen: macOpenFiles.map(file => this.getWindowOpenableFromPathSync(file)), + noRecentEntry, + waitMarkerFileURI, + initialStartup: true, + // remoteAuthority: will be determined based on macOpenFiles + }); + } } // default: read paths from cli @@ -993,11 +1032,13 @@ export class CodeApplication extends Disposable { cli: args, forceNewWindow: args['new-window'] || (!hasCliArgs && args['unity-launch']), diffMode: args.diff, + mergeMode: args.merge, noRecentEntry, waitMarkerFileURI, gotoLineMode: args.goto, initialStartup: true, - remoteAuthority + remoteAuthority, + profile }); } @@ -1085,15 +1126,59 @@ export class CodeApplication extends Disposable { return { fileUri: URI.file(path) }; } - private async afterWindowOpen(accessor: ServicesAccessor, sharedProcess: SharedProcess): Promise { + private afterWindowOpen(accessor: ServicesAccessor, sharedProcess: SharedProcess): void { + const telemetryService = accessor.get(ITelemetryService); + const updateService = accessor.get(IUpdateService); // Signal phase: after window open this.lifecycleMainService.phase = LifecycleMainPhase.AfterWindowOpen; // Observe shared process for errors + this.handleSharedProcessErrors(telemetryService, sharedProcess); + + // Windows: mutex + this.installMutex(); + + // Remote Authorities + protocol.registerHttpProtocol(Schemas.vscodeRemoteResource, (request, callback) => { + callback({ + url: request.url.replace(/^vscode-remote-resource:/, 'http:'), + method: request.method + }); + }); + + // Initialize update service + if (updateService instanceof Win32UpdateService || updateService instanceof LinuxUpdateService || updateService instanceof DarwinUpdateService) { + updateService.initialize(); + } + + // Start to fetch shell environment (if needed) after window has opened + // Since this operation can take a long time, we want to warm it up while + // the window is opening. + // We also show an error to the user in case this fails. + this.resolveShellEnvironment(this.environmentMainService.args, process.env, true); + + // Crash reporter + this.updateCrashReporterEnablement(); + } + + private async installMutex(): Promise { + const win32MutexName = this.productService.win32MutexName; + if (isWindows && win32MutexName) { + try { + const WindowsMutex = await import('windows-mutex'); + const mutex = new WindowsMutex.Mutex(win32MutexName); + once(this.lifecycleMainService.onWillShutdown)(() => mutex.release()); + } catch (error) { + this.logService.error(error); + } + } + } + + private handleSharedProcessErrors(telemetryService: ITelemetryService, sharedProcess: SharedProcess): void { let willShutdown = false; once(this.lifecycleMainService.onWillShutdown)(() => willShutdown = true); - const telemetryService = accessor.get(ITelemetryService); + this._register(sharedProcess.onDidError(({ type, details }) => { // Logging @@ -1137,67 +1222,6 @@ export class CodeApplication extends Disposable { shuttingdown: willShutdown }); })); - - // Windows: install mutex - const win32MutexName = this.productService.win32MutexName; - if (isWindows && win32MutexName) { - try { - const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex; - const mutex = new WindowsMutex(win32MutexName); - once(this.lifecycleMainService.onWillShutdown)(() => mutex.release()); - } catch (error) { - this.logService.error(error); - } - } - - // Remote Authorities - protocol.registerHttpProtocol(Schemas.vscodeRemoteResource, (request, callback) => { - callback({ - url: request.url.replace(/^vscode-remote-resource:/, 'http:'), - method: request.method - }); - }); - - // Initialize update service - const updateService = accessor.get(IUpdateService); - if (updateService instanceof Win32UpdateService || updateService instanceof LinuxUpdateService || updateService instanceof DarwinUpdateService) { - updateService.initialize(); - } - - // Start to fetch shell environment (if needed) after window has opened - // Since this operation can take a long time, we want to warm it up while - // the window is opening. - // We also show an error to the user in case this fails. - this.resolveShellEnvironment(this.environmentMainService.args, process.env, true); - - // If enable-crash-reporter argv is undefined then this is a fresh start, - // based on telemetry.enableCrashreporter settings, generate a UUID which - // will be used as crash reporter id and also update the json file. - try { - const argvContent = await this.fileService.readFile(this.environmentMainService.argvResource); - const argvString = argvContent.value.toString(); - const argvJSON = JSON.parse(stripComments(argvString)); - if (argvJSON['enable-crash-reporter'] === undefined) { - const telemetryLevel = getTelemetryLevel(this.configurationService); - const enableCrashReporter = telemetryLevel >= TelemetryLevel.CRASH; - const additionalArgvContent = [ - '', - ' // Allows to disable crash reporting.', - ' // Should restart the app if the value is changed.', - ` "enable-crash-reporter": ${enableCrashReporter},`, - '', - ' // Unique id used for correlating crash reports sent from this instance.', - ' // Do not edit this value.', - ` "crash-reporter-id": "${generateUuid()}"`, - '}' - ]; - const newArgvString = argvString.substring(0, argvString.length - 2).concat(',\n', additionalArgvContent.join('\n')); - - await this.fileService.writeFile(this.environmentMainService.argvResource, VSBuffer.fromString(newArgvString)); - } - } catch (error) { - this.logService.error(error); - } } private async resolveShellEnvironment(args: NativeParsedArgs, env: IProcessEnvironment, notifyOnError: boolean): Promise { @@ -1215,6 +1239,49 @@ export class CodeApplication extends Disposable { return {}; } + private async updateCrashReporterEnablement(): Promise { + + // If enable-crash-reporter argv is undefined then this is a fresh start, + // based on `telemetry.enableCrashreporter` settings, generate a UUID which + // will be used as crash reporter id and also update the json file. + + try { + const argvContent = await this.fileService.readFile(this.environmentMainService.argvResource); + const argvString = argvContent.value.toString(); + const argvJSON = JSON.parse(stripComments(argvString)); + const telemetryLevel = getTelemetryLevel(this.configurationService); + const enableCrashReporter = telemetryLevel >= TelemetryLevel.CRASH; + + // Initial startup + if (argvJSON['enable-crash-reporter'] === undefined) { + const additionalArgvContent = [ + '', + ' // Allows to disable crash reporting.', + ' // Should restart the app if the value is changed.', + ` "enable-crash-reporter": ${enableCrashReporter},`, + '', + ' // Unique id used for correlating crash reports sent from this instance.', + ' // Do not edit this value.', + ` "crash-reporter-id": "${generateUuid()}"`, + '}' + ]; + const newArgvString = argvString.substring(0, argvString.length - 2).concat(',\n', additionalArgvContent.join('\n')); + + await this.fileService.writeFile(this.environmentMainService.argvResource, VSBuffer.fromString(newArgvString)); + } + + // Subsequent startup: update crash reporter value if changed + else { + const newArgvString = argvString.replace(/"enable-crash-reporter": .*,/, `"enable-crash-reporter": ${enableCrashReporter},`); + if (newArgvString !== argvString) { + await this.fileService.writeFile(this.environmentMainService.argvResource, VSBuffer.fromString(newArgvString)); + } + } + } catch (error) { + this.logService.error(error); + } + } + private stopTracingEventually(accessor: ServicesAccessor, windows: ICodeWindow[]): void { this.logService.info('Tracing: waiting for windows to get ready...'); @@ -1255,4 +1322,3 @@ export class CodeApplication extends Disposable { }); } } - diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 1a4f72bd620..d2e59149d7d 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -103,7 +103,7 @@ class CodeMain { // Init services try { - await this.initServices(environmentMainService, userDataProfilesMainService, configurationService, stateMainService); + await this.initServices(environmentMainService, userDataProfilesMainService, configurationService, stateMainService, productService); } catch (error) { // Show a dialog for errors that can be resolved by the user @@ -198,22 +198,22 @@ class CodeMain { services.set(IConfigurationService, configurationService); // Lifecycle - services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService)); + services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService, undefined, false)); // Request - services.set(IRequestService, new SyncDescriptor(RequestMainService)); + services.set(IRequestService, new SyncDescriptor(RequestMainService, undefined, true)); // Themes services.set(IThemeMainService, new SyncDescriptor(ThemeMainService)); // Signing - services.set(ISignService, new SyncDescriptor(SignService)); + services.set(ISignService, new SyncDescriptor(SignService, undefined, false /* proxied to other processes */)); // Tunnel services.set(ITunnelService, new SyncDescriptor(TunnelService)); - // Protocol - services.set(IProtocolMainService, new SyncDescriptor(ProtocolMainService)); + // Protocol (instantiated early and not using sync descriptor for security reasons) + services.set(IProtocolMainService, new ProtocolMainService(environmentMainService, userDataProfilesMainService, logService)); return [new InstantiationService(services, true), instanceEnvironment, environmentMainService, configurationService, stateMainService, bufferLogService, productService, userDataProfilesMainService]; } @@ -235,7 +235,7 @@ class CodeMain { return instanceEnvironment; } - private async initServices(environmentMainService: IEnvironmentMainService, userDataProfilesMainService: UserDataProfilesMainService, configurationService: ConfigurationService, stateMainService: StateMainService): Promise { + private async initServices(environmentMainService: IEnvironmentMainService, userDataProfilesMainService: UserDataProfilesMainService, configurationService: ConfigurationService, stateMainService: StateMainService, productService: IProductService): Promise { await Promises.settled([ // Environment service (paths) @@ -256,7 +256,7 @@ class CodeMain { configurationService.initialize() ]); - userDataProfilesMainService.setEnablement(!!configurationService.getValue(PROFILES_ENABLEMENT_CONFIG)); + userDataProfilesMainService.setEnablement(productService.quality !== 'stable' || configurationService.getValue(PROFILES_ENABLEMENT_CONFIG)); } private async claimInstance(logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise { @@ -346,9 +346,9 @@ class CodeMain { if (environmentMainService.args.status) { return instantiationService.invokeFunction(async () => { const diagnosticsService = new DiagnosticsService(NullTelemetryService, productService); - const mainProcessInfo = await otherInstanceLaunchMainService.getMainProcessInfo(); + const mainDiagnostics = await otherInstanceDiagnosticsMainService.getMainDiagnostics(); const remoteDiagnostics = await otherInstanceDiagnosticsMainService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true }); - const diagnostics = await diagnosticsService.getDiagnostics(mainProcessInfo, remoteDiagnostics); + const diagnostics = await diagnosticsService.getDiagnostics(mainDiagnostics, remoteDiagnostics); console.log(diagnostics); throw new ExpectedError(); diff --git a/src/vs/code/electron-sandbox/issue/issueReporterMain.ts b/src/vs/code/electron-sandbox/issue/issueReporterMain.ts index 4037fbb3441..33e66bedc76 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterMain.ts +++ b/src/vs/code/electron-sandbox/issue/issueReporterMain.ts @@ -27,7 +27,9 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { NativeHostService } from 'vs/platform/native/electron-sandbox/nativeHostService'; import { applyZoom, zoomIn, zoomOut } from 'vs/platform/window/electron-sandbox/window'; -const MAX_URL_LENGTH = 2045; +// GitHub has let us know that we could up our limit here to 8k. We chose 7500 to play it safe. +// ref https://github.com/microsoft/vscode/issues/159191 +const MAX_URL_LENGTH = 7500; interface SearchResult { html_url: string; @@ -71,8 +73,9 @@ export class IssueReporter extends Disposable { const mainProcessService = new ElectronIPCMainProcessService(configuration.windowId); this.nativeHostService = new NativeHostService(configuration.windowId, mainProcessService) as INativeHostService; - const targetExtension = configuration.data.extensionId ? configuration.data.enabledExtensions.find(extension => extension.id === configuration.data.extensionId) : undefined; + const targetExtension = configuration.data.extensionId ? configuration.data.enabledExtensions.find(extension => extension.id.toLocaleLowerCase() === configuration.data.extensionId?.toLocaleLowerCase()) : undefined; this.issueReporterModel = new IssueReporterModel({ + ...configuration.data, issueType: configuration.data.issueType || IssueType.Bug, versionInfo: { vscodeVersion: `${configuration.product.nameShort} ${!!configuration.product.darwinUniversalAssetId ? `${configuration.product.version} (Universal)` : configuration.product.version} (${configuration.product.commit || 'Commit unknown'}, ${configuration.product.date || 'Date unknown'})`, @@ -80,7 +83,7 @@ export class IssueReporter extends Disposable { }, extensionsDisabled: !!configuration.disableExtensions, fileOnExtension: configuration.data.extensionId ? !targetExtension?.isBuiltin : undefined, - selectedExtension: targetExtension, + selectedExtension: targetExtension }); const issueReporterElement = this.getElementById('issue-reporter'); @@ -140,6 +143,7 @@ export class IssueReporter extends Disposable { this.handleExtensionData(configuration.data.enabledExtensions); this.updateExperimentsInfo(configuration.data.experiments); this.updateRestrictedMode(configuration.data.restrictedMode); + this.updateUnsupportedMode(configuration.data.isUnsupported); } render(): void { @@ -150,14 +154,10 @@ export class IssueReporter extends Disposable { const { fileOnExtension } = this.issueReporterModel.getData(); if (fileOnExtension) { const issueTitle = document.getElementById('issue-title'); - if (issueTitle) { - issueTitle.focus(); - } + issueTitle?.focus(); } else { const issueType = document.getElementById('issue-type'); - if (issueType) { - issueType.focus(); - } + issueType?.focus(); } } @@ -729,7 +729,7 @@ export class IssueReporter extends Disposable { } else if (!fileOnMarketplace) { show(extensionsBlock); } - reset(descriptionTitle, localize('stepsToReproduce', "Steps to Reproduce"), $('span.required-input', undefined, '*')); + reset(descriptionTitle, localize('stepsToReproduce', "Steps to Reproduce") + ' ', $('span.required-input', undefined, '*')); reset(descriptionSubtitle, localize('bugDescription', "Share the steps needed to reliably reproduce the problem. Please include actual and expected results. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.")); } else if (issueType === IssueType.PerformanceIssue) { show(problemSource); @@ -748,10 +748,10 @@ export class IssueReporter extends Disposable { show(extensionsBlock); } - reset(descriptionTitle, localize('stepsToReproduce', "Steps to Reproduce"), $('span.required-input', undefined, '*')); + reset(descriptionTitle, localize('stepsToReproduce', "Steps to Reproduce") + ' ', $('span.required-input', undefined, '*')); reset(descriptionSubtitle, localize('performanceIssueDesciption', "When did this performance issue happen? Does it occur on startup or after a specific series of actions? We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.")); } else if (issueType === IssueType.FeatureRequest) { - reset(descriptionTitle, localize('description', "Description"), $('span.required-input', undefined, '*')); + reset(descriptionTitle, localize('description', "Description") + ' ', $('span.required-input', undefined, '*')); reset(descriptionSubtitle, localize('featureRequestDescription', "Please describe the feature you would like to see. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.")); show(problemSource); @@ -1154,6 +1154,10 @@ export class IssueReporter extends Disposable { this.issueReporterModel.update({ restrictedMode }); } + private updateUnsupportedMode(isUnsupported: boolean) { + this.issueReporterModel.update({ isUnsupported }); + } + private updateExperimentsInfo(experimentInfo: string | undefined) { this.issueReporterModel.update({ experimentInfo }); const target = document.querySelector('.block-experiments .block-info'); diff --git a/src/vs/code/electron-sandbox/issue/issueReporterModel.ts b/src/vs/code/electron-sandbox/issue/issueReporterModel.ts index 37a1a40beb0..a58acca2f5a 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterModel.ts +++ b/src/vs/code/electron-sandbox/issue/issueReporterModel.ts @@ -33,6 +33,8 @@ export interface IssueReporterData { filterResultCount?: number; experimentInfo?: string; restrictedMode?: boolean; + isUnsupported?: boolean; + isSandboxed?: boolean; } export class IssueReporterModel { @@ -61,14 +63,22 @@ export class IssueReporterModel { } serialize(): string { + const modes = []; + if (this._data.restrictedMode) { + modes.push('Restricted'); + } + if (this._data.isUnsupported) { + modes.push('Unsupported'); + } return ` -Issue Type: ${this.getIssueTypeTitle()} +Type: ${this.getIssueTypeTitle()} ${this._data.issueDescription} ${this.getExtensionVersion()} VS Code version: ${this._data.versionInfo && this._data.versionInfo.vscodeVersion} OS version: ${this._data.versionInfo && this._data.versionInfo.os} -Restricted Mode: ${this._data.restrictedMode ? 'Yes' : 'No'} +Modes:${modes.length ? ' ' + modes.join(', ') : ''} +Sandboxed: ${this._data.isSandboxed ? 'Yes' : 'No'} ${this.getRemoteOSes()} ${this.getInfos()} `; diff --git a/src/vs/code/electron-sandbox/issue/issueReporterPage.ts b/src/vs/code/electron-sandbox/issue/issueReporterPage.ts index 99e6cc82420..6467d66bd36 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterPage.ts +++ b/src/vs/code/electron-sandbox/issue/issueReporterPage.ts @@ -11,11 +11,23 @@ const sendProcessInfoLabel = escape(localize('sendProcessInfo', "Include my curr const sendWorkspaceInfoLabel = escape(localize('sendWorkspaceInfo', "Include my workspace metadata")); const sendExtensionsLabel = escape(localize('sendExtensions', "Include my enabled extensions")); const sendExperimentsLabel = escape(localize('sendExperiments', "Include A/B experiment info")); +const reviewGuidanceLabel = localize( // intentionally not escaped because of its embedded tags + { + key: 'reviewGuidanceLabel', + comment: [ + '{Locked=""}', + '{Locked=""}' + ] + }, + 'Before you report an issue here please review the guidance we provide.' +); export default (): string => `
+
${reviewGuidanceLabel}
+
@@ -25,7 +37,7 @@ export default (): string => `
- + diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts b/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts index 8e756e829d9..2fcf59e3ae0 100644 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts @@ -257,6 +257,7 @@ class ProcessExplorer { await this.createProcessTree(processRoots); } else { this.tree.setInput({ processes: { processRoots } }); + this.tree.layout(window.innerHeight, window.innerWidth); } this.requestProcessList(0); @@ -342,6 +343,13 @@ class ProcessExplorer { this.showContextMenu(e.element, true); } }); + + container.style.height = `${window.innerHeight}px`; + + window.addEventListener('resize', () => { + container.style.height = `${window.innerHeight}px`; + this.tree?.layout(window.innerHeight, window.innerWidth); + }); } private isDebuggable(cmd: string): boolean { @@ -416,6 +424,47 @@ class ProcessExplorer { content.push(`.monaco-list-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`); } + // Scrollbars + if (styles.scrollbarShadowColor) { + content.push(` + .monaco-scrollable-element > .shadow.top { + box-shadow: ${styles.scrollbarShadowColor} 0 6px 6px -6px inset; + } + + .monaco-scrollable-element > .shadow.left { + box-shadow: ${styles.scrollbarShadowColor} 6px 0 6px -6px inset; + } + + .monaco-scrollable-element > .shadow.top.left { + box-shadow: ${styles.scrollbarShadowColor} 6px 6px 6px -6px inset; + } + `); + } + + if (styles.scrollbarSliderBackgroundColor) { + content.push(` + .monaco-scrollable-element > .scrollbar > .slider { + background: ${styles.scrollbarSliderBackgroundColor}; + } + `); + } + + if (styles.scrollbarSliderHoverBackgroundColor) { + content.push(` + .monaco-scrollable-element > .scrollbar > .slider:hover { + background: ${styles.scrollbarSliderHoverBackgroundColor}; + } + `); + } + + if (styles.scrollbarSliderActiveBackgroundColor) { + content.push(` + .monaco-scrollable-element > .scrollbar > .slider.active { + background: ${styles.scrollbarSliderActiveBackgroundColor}; + } + `); + } + styleElement.textContent = content.join('\n'); if (styles.color) { diff --git a/src/vs/code/electron-sandbox/workbench/workbench.html b/src/vs/code/electron-sandbox/workbench/workbench.html index 47066f520be..16e089df650 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.html +++ b/src/vs/code/electron-sandbox/workbench/workbench.html @@ -4,7 +4,7 @@ - + diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.js index e271fdf1bf4..c8e4431d6db 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.js +++ b/src/vs/code/electron-sandbox/workbench/workbench.js @@ -16,10 +16,10 @@ // Load workbench main JS, CSS and NLS all in parallel. This is an // optimization to prevent a waterfall of loading to happen, because - // we know for a fact that workbench.desktop.sandbox.main will depend on + // we know for a fact that workbench.desktop.main will depend on // the related CSS and NLS counterparts. bootstrapWindow.load([ - 'vs/workbench/workbench.desktop.sandbox.main', + 'vs/workbench/workbench.desktop.main', 'vs/nls!vs/workbench/workbench.desktop.main', 'vs/css!vs/workbench/workbench.desktop.main' ], @@ -36,7 +36,7 @@ return { // disable automated devtools opening on error when running extension tests // as this can lead to nondeterministic test execution (devtools steals focus) - forceDisableShowDevtoolsOnError: typeof windowConfig.extensionTestsPath === 'string', + forceDisableShowDevtoolsOnError: typeof windowConfig.extensionTestsPath === 'string' || windowConfig['enable-smoke-test-driver'] === true, // enable devtools keybindings in extension development window forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath) && windowConfig.extensionDevelopmentPath.length > 0, removeDeveloperKeybindingsAfterLoad: true @@ -61,7 +61,7 @@ window.requestIdleCallback(() => { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); - context.clearRect(0, 0, canvas.width, canvas.height); + context?.clearRect(0, 0, canvas.width, canvas.height); canvas.remove(); }, { timeout: 50 }); } diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 80e5dec517d..190d64038e9 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -8,7 +8,7 @@ import { chmodSync, existsSync, readFileSync, statSync, truncateSync, unlinkSync import { homedir, release, tmpdir } from 'os'; import type { ProfilingSession, Target } from 'v8-inspect-profiler'; import { Event } from 'vs/base/common/event'; -import { isAbsolute, resolve } from 'vs/base/common/path'; +import { isAbsolute, resolve, join } from 'vs/base/common/path'; import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform'; import { randomPort } from 'vs/base/common/ports'; import { isString } from 'vs/base/common/types'; @@ -24,6 +24,8 @@ import product from 'vs/platform/product/common/product'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { randomPath } from 'vs/base/common/extpath'; import { Utils } from 'vs/platform/profiling/common/profiling'; +import { dirname } from 'vs/base/common/resources'; +import { FileAccess } from 'vs/base/common/network'; function shouldSpawnCliProcess(argv: NativeParsedArgs): boolean { return !!argv['install-source'] @@ -59,6 +61,23 @@ export async function main(argv: string[]): Promise { console.log(buildVersionMessage(product.version, product.commit)); } + // Shell integration + else if (args['locate-shell-integration-path']) { + let file: string; + switch (args['locate-shell-integration-path']) { + // Usage: `[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path bash)"` + case 'bash': file = 'shellIntegration-bash.sh'; break; + // Usage: `if ($env:TERM_PROGRAM -eq "vscode") { . "$(code --locate-shell-integration-path pwsh)" }` + case 'pwsh': file = 'shellIntegration.ps1'; break; + // Usage: `[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path zsh)"` + case 'zsh': file = 'shellIntegration-rc.zsh'; break; + // Usage: `string match -q "$TERM_PROGRAM" "vscode"; and . (code --locate-shell-integration-path fish)` + case 'fish': file = 'shellIntegration.fish'; break; + default: throw new Error('Error using --locate-shell-integration-path: Invalid shell type'); + } + console.log(join(dirname(FileAccess.asFileUri('', require)).fsPath, 'out', 'vs', 'workbench', 'contrib', 'terminal', 'browser', 'media', file)); + } + // Extensions Management else if (shouldSpawnCliProcess(args)) { const cli = await new Promise((resolve, reject) => require(['vs/code/node/cliProcessMain'], resolve, reject)); @@ -162,7 +181,7 @@ export async function main(argv: string[]): Promise { // returns a file path where stdin input is written into (write in progress). try { - readFromStdin(stdinFilePath, !!verbose); // throws error if file can not be written + await readFromStdin(stdinFilePath, !!verbose); // throws error if file can not be written // Make sure to open tmp file addArg(argv, stdinFilePath); diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index bc4ca25f492..83b93b7898d 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -23,8 +23,8 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; import { ExtensionGalleryServiceWithNoStorageService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; -import { IExtensionGalleryService, IExtensionManagementCLIService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService'; +import { IExtensionGalleryService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionManagementCLI } from 'vs/platform/extensionManagement/common/extensionManagementCLI'; import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService'; import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; @@ -52,8 +52,8 @@ import { StateService } from 'vs/platform/state/node/stateService'; import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties'; import { ITelemetryService, machineIdKey } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils'; -import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; +import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; +import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; import { buildTelemetryMessage } from 'vs/platform/telemetry/node/telemetry'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; @@ -85,7 +85,7 @@ class CliMain extends Disposable { const logService = accessor.get(ILogService); const fileService = accessor.get(IFileService); const environmentService = accessor.get(INativeEnvironmentService); - const extensionManagementCLIService = accessor.get(IExtensionManagementCLIService); + const userDataProfilesService = accessor.get(IUserDataProfilesService); // Log info logService.info('CLI main', this.argv); @@ -94,7 +94,7 @@ class CliMain extends Disposable { this.registerErrorHandler(logService); // Run based on argv - await this.doRun(environmentService, extensionManagementCLIService, fileService); + await this.doRun(environmentService, fileService, userDataProfilesService, instantiationService); // Flush the remaining data in AI adapter (with 1s timeout) await Promise.all(appenders.map(a => { @@ -104,7 +104,7 @@ class CliMain extends Disposable { }); } - private async initServices(): Promise<[IInstantiationService, AppInsightsAppender[]]> { + private async initServices(): Promise<[IInstantiationService, OneDataSystemAppender[]]> { const services = new ServiceCollection(); // Product @@ -164,32 +164,32 @@ class CliMain extends Disposable { configurationService.initialize() ]); - userDataProfilesService.setEnablement(!!configurationService.getValue(PROFILES_ENABLEMENT_CONFIG)); + userDataProfilesService.setEnablement(productService.quality !== 'stable' || configurationService.getValue(PROFILES_ENABLEMENT_CONFIG)); // URI Identity services.set(IUriIdentityService, new UriIdentityService(fileService)); // Request - services.set(IRequestService, new SyncDescriptor(RequestService)); + services.set(IRequestService, new SyncDescriptor(RequestService, undefined, true)); // Download Service - services.set(IDownloadService, new SyncDescriptor(DownloadService)); + services.set(IDownloadService, new SyncDescriptor(DownloadService, undefined, true)); // Extensions - services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService)); - services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService)); - services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); - services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService)); - services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService)); + services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService, undefined, true)); + services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService, undefined, true)); + services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService, undefined, true)); + services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService, undefined, true)); // Localizations - services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService)); + services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService, undefined, false)); // Telemetry - const appenders: AppInsightsAppender[] = []; + const appenders: OneDataSystemAppender[] = []; + const isInternal = isInternalTelemetry(productService, configurationService); if (supportsTelemetry(productService, environmentService)) { - if (productService.aiConfig && productService.aiConfig.asimovKey) { - appenders.push(new AppInsightsAppender('monacoworkbench', null, productService.aiConfig.asimovKey)); + if (productService.aiConfig && productService.aiConfig.ariaKey) { + appenders.push(new OneDataSystemAppender(isInternal, 'monacoworkbench', null, productService.aiConfig.ariaKey)); } const { installSourcePath } = environmentService; @@ -208,12 +208,12 @@ class CliMain extends Disposable { } } - return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, productService.msftInternalDomains, installSourcePath); + return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, isInternal, installSourcePath); })(), piiPaths: getPiiPathsFromEnvironment(environmentService) }; - services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); + services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config], false)); } else { services.set(ITelemetryService, NullTelemetryService); @@ -239,7 +239,8 @@ class CliMain extends Disposable { process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason)); } - private async doRun(environmentService: INativeEnvironmentService, extensionManagementCLIService: IExtensionManagementCLIService, fileService: IFileService): Promise { + private async doRun(environmentService: INativeEnvironmentService, fileService: IFileService, userDataProfilesService: IUserDataProfilesService, instantiationService: IInstantiationService): Promise { + const profileLocation = environmentService.args.profile ? userDataProfilesService.profiles.find(p => p.name === environmentService.args.profile)?.extensionsResource : userDataProfilesService.defaultProfile.extensionsResource; // Install Source if (this.argv['install-source']) { @@ -248,23 +249,23 @@ class CliMain extends Disposable { // List Extensions if (this.argv['list-extensions']) { - return extensionManagementCLIService.listExtensions(!!this.argv['show-versions'], this.argv['category']); + return instantiationService.createInstance(ExtensionManagementCLI).listExtensions(!!this.argv['show-versions'], this.argv['category'], profileLocation); } // Install Extension else if (this.argv['install-extension'] || this.argv['install-builtin-extension']) { - const installOptions: InstallOptions = { isMachineScoped: !!this.argv['do-not-sync'], installPreReleaseVersion: !!this.argv['pre-release'] }; - return extensionManagementCLIService.installExtensions(this.asExtensionIdOrVSIX(this.argv['install-extension'] || []), this.argv['install-builtin-extension'] || [], installOptions, !!this.argv['force']); + const installOptions: InstallOptions = { isMachineScoped: !!this.argv['do-not-sync'], installPreReleaseVersion: !!this.argv['pre-release'], profileLocation }; + return instantiationService.createInstance(ExtensionManagementCLI).installExtensions(this.asExtensionIdOrVSIX(this.argv['install-extension'] || []), this.argv['install-builtin-extension'] || [], installOptions, !!this.argv['force']); } // Uninstall Extension else if (this.argv['uninstall-extension']) { - return extensionManagementCLIService.uninstallExtensions(this.asExtensionIdOrVSIX(this.argv['uninstall-extension']), !!this.argv['force']); + return instantiationService.createInstance(ExtensionManagementCLI).uninstallExtensions(this.asExtensionIdOrVSIX(this.argv['uninstall-extension']), !!this.argv['force'], profileLocation); } // Locate Extension else if (this.argv['locate-extension']) { - return extensionManagementCLIService.locateExtension(this.argv['locate-extension']); + return instantiationService.createInstance(ExtensionManagementCLI).locateExtension(this.argv['locate-extension']); } // Telemetry diff --git a/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts b/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts index 87bca75fedf..aa0fac7bf0d 100644 --- a/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts +++ b/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts @@ -27,13 +27,14 @@ suite('IssueReporter', () => { const issueReporterModel = new IssueReporterModel({}); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes: +Sandboxed: No Extensions: none `); @@ -58,13 +59,14 @@ Extensions: none }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes: +Sandboxed: No
System Info @@ -102,13 +104,14 @@ Restricted Mode: No }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes: +Sandboxed: No
System Info @@ -157,13 +160,14 @@ vsins829:30139715 }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes: +Sandboxed: No
System Info @@ -214,13 +218,14 @@ Restricted Mode: No }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes: +Sandboxed: No Remote OS version: Linux x64 4.18.0
@@ -263,13 +268,14 @@ Remote OS version: Linux x64 4.18.0 }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes: +Sandboxed: No
System Info @@ -287,6 +293,25 @@ Restricted Mode: No `); }); + test('should supply mode if applicable', () => { + const issueReporterModel = new IssueReporterModel({ + isUnsupported: true, + restrictedMode: true + }); + assert.strictEqual(issueReporterModel.serialize(), + ` +Type: Bug + +undefined + +VS Code version: undefined +OS version: undefined +Modes: Restricted, Unsupported +Sandboxed: No + +Extensions: none +`); + }); test('should normalize GitHub urls', () => { [ 'https://github.com/repo', diff --git a/src/vs/editor/browser/config/migrateOptions.ts b/src/vs/editor/browser/config/migrateOptions.ts index 49d6a503a84..84abd167ef6 100644 --- a/src/vs/editor/browser/config/migrateOptions.ts +++ b/src/vs/editor/browser/config/migrateOptions.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { forEach } from 'vs/base/common/collections'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; export interface ISettingsReader { @@ -152,14 +151,14 @@ const suggestFilteredTypesMapping: Record = { registerEditorSettingMigration('suggest.filteredTypes', (value, read, write) => { if (value && typeof value === 'object') { - forEach(suggestFilteredTypesMapping, entry => { - const v = value[entry.key]; + for (const entry of Object.entries(suggestFilteredTypesMapping)) { + const v = value[entry[0]]; if (v === false) { - if (typeof read(`suggest.${entry.value}`) === 'undefined') { - write(`suggest.${entry.value}`, false); + if (typeof read(`suggest.${entry[1]}`) === 'undefined') { + write(`suggest.${entry[1]}`, false); } } - }); + } write('suggest.filteredTypes', undefined); } }); @@ -171,3 +170,23 @@ registerEditorSettingMigration('quickSuggestions', (input, read, write) => { write('quickSuggestions', newValue); } }); + +// Sticky Scroll + +registerEditorSettingMigration('experimental.stickyScroll.enabled', (value, read, write) => { + if (typeof value === 'boolean') { + write('experimental.stickyScroll.enabled', undefined); + if (typeof read('stickyScroll.enabled') === 'undefined') { + write('stickyScroll.enabled', value); + } + } +}); + +registerEditorSettingMigration('experimental.stickyScroll.maxLineCount', (value, read, write) => { + if (typeof value === 'number') { + write('experimental.stickyScroll.maxLineCount', undefined); + if (typeof read('stickyScroll.maxLineCount') === 'undefined') { + write('stickyScroll.maxLineCount', value); + } + } +}); diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 3e7e9a3252e..1e785855191 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -5,6 +5,7 @@ import * as browser from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; +import { DomEmitter } from 'vs/base/browser/event'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { RunOnceScheduler } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; @@ -672,19 +673,19 @@ class ClipboardEventUtils { export class TextAreaWrapper extends Disposable implements ICompleteTextAreaWrapper { - public readonly onKeyDown = this._register(dom.createEventEmitter(this._actual, 'keydown')).event; - public readonly onKeyPress = this._register(dom.createEventEmitter(this._actual, 'keypress')).event; - public readonly onKeyUp = this._register(dom.createEventEmitter(this._actual, 'keyup')).event; - public readonly onCompositionStart = this._register(dom.createEventEmitter(this._actual, 'compositionstart')).event; - public readonly onCompositionUpdate = this._register(dom.createEventEmitter(this._actual, 'compositionupdate')).event; - public readonly onCompositionEnd = this._register(dom.createEventEmitter(this._actual, 'compositionend')).event; - public readonly onBeforeInput = this._register(dom.createEventEmitter(this._actual, 'beforeinput')).event; - public readonly onInput = >this._register(dom.createEventEmitter(this._actual, 'input')).event; - public readonly onCut = this._register(dom.createEventEmitter(this._actual, 'cut')).event; - public readonly onCopy = this._register(dom.createEventEmitter(this._actual, 'copy')).event; - public readonly onPaste = this._register(dom.createEventEmitter(this._actual, 'paste')).event; - public readonly onFocus = this._register(dom.createEventEmitter(this._actual, 'focus')).event; - public readonly onBlur = this._register(dom.createEventEmitter(this._actual, 'blur')).event; + public readonly onKeyDown = this._register(new DomEmitter(this._actual, 'keydown')).event; + public readonly onKeyPress = this._register(new DomEmitter(this._actual, 'keypress')).event; + public readonly onKeyUp = this._register(new DomEmitter(this._actual, 'keyup')).event; + public readonly onCompositionStart = this._register(new DomEmitter(this._actual, 'compositionstart')).event; + public readonly onCompositionUpdate = this._register(new DomEmitter(this._actual, 'compositionupdate')).event; + public readonly onCompositionEnd = this._register(new DomEmitter(this._actual, 'compositionend')).event; + public readonly onBeforeInput = this._register(new DomEmitter(this._actual, 'beforeinput')).event; + public readonly onInput = >this._register(new DomEmitter(this._actual, 'input')).event; + public readonly onCut = this._register(new DomEmitter(this._actual, 'cut')).event; + public readonly onCopy = this._register(new DomEmitter(this._actual, 'copy')).event; + public readonly onPaste = this._register(new DomEmitter(this._actual, 'paste')).event; + public readonly onFocus = this._register(new DomEmitter(this._actual, 'focus')).event; + public readonly onBlur = this._register(new DomEmitter(this._actual, 'blur')).event; private _onSyntheticTap = this._register(new Emitter()); public readonly onSyntheticTap: Event = this._onSyntheticTap.event; diff --git a/src/vs/editor/browser/coreCommands.ts b/src/vs/editor/browser/coreCommands.ts index ecc72a1a366..b5ab2a699e1 100644 --- a/src/vs/editor/browser/coreCommands.ts +++ b/src/vs/editor/browser/coreCommands.ts @@ -84,7 +84,7 @@ export namespace EditorScroll_ { \`\`\` * 'by': Unit to move. Default is computed based on 'to' value. \`\`\` - 'line', 'wrappedLine', 'page', 'halfPage' + 'line', 'wrappedLine', 'page', 'halfPage', 'editor' \`\`\` * 'value': Number of units to move. Default is '1'. * 'revealCursor': If 'true' reveals the cursor if it is outside view port. @@ -100,7 +100,7 @@ export namespace EditorScroll_ { }, 'by': { 'type': 'string', - 'enum': ['line', 'wrappedLine', 'page', 'halfPage'] + 'enum': ['line', 'wrappedLine', 'page', 'halfPage', 'editor'] }, 'value': { 'type': 'number', @@ -130,7 +130,8 @@ export namespace EditorScroll_ { Line: 'line', WrappedLine: 'wrappedLine', Page: 'page', - HalfPage: 'halfPage' + HalfPage: 'halfPage', + Editor: 'editor' }; /** @@ -172,6 +173,9 @@ export namespace EditorScroll_ { case RawUnit.HalfPage: unit = Unit.HalfPage; break; + case RawUnit.Editor: + unit = Unit.Editor; + break; default: unit = Unit.WrappedLine; } @@ -205,7 +209,8 @@ export namespace EditorScroll_ { Line = 1, WrappedLine = 2, Page = 3, - HalfPage = 4 + HalfPage = 4, + Editor = 5 } } @@ -1279,6 +1284,14 @@ export namespace CoreNavigationCommands { return viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber); } + if (args.unit === EditorScroll_.Unit.Editor) { + let desiredTopModelLineNumber = 0; + if (args.direction === EditorScroll_.Direction.Down) { + desiredTopModelLineNumber = viewModel.model.getLineCount() - viewModel.cursorConfig.pageSize; + } + return viewModel.viewLayout.getVerticalOffsetForLineNumber(desiredTopModelLineNumber); + } + let noOfLines: number; if (args.unit === EditorScroll_.Unit.Page) { noOfLines = viewModel.cursorConfig.pageSize * args.value; @@ -1345,6 +1358,29 @@ export namespace CoreNavigationCommands { } }); + export const ScrollEditorTop: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + constructor() { + super({ + id: 'scrollEditorTop', + precondition: undefined, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: EditorContextKeys.textInputFocus, + } + }); + } + + runCoreEditorCommand(viewModel: IViewModel, args: any): void { + EditorScroll._runEditorScroll(viewModel, args.source, { + direction: EditorScroll_.Direction.Up, + unit: EditorScroll_.Unit.Editor, + value: 1, + revealCursor: false, + select: false + }); + } + }); + export const ScrollLineDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ @@ -1396,6 +1432,29 @@ export namespace CoreNavigationCommands { } }); + export const ScrollEditorBottom: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + constructor() { + super({ + id: 'scrollEditorBottom', + precondition: undefined, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: EditorContextKeys.textInputFocus, + } + }); + } + + runCoreEditorCommand(viewModel: IViewModel, args: any): void { + EditorScroll._runEditorScroll(viewModel, args.source, { + direction: EditorScroll_.Direction.Down, + unit: EditorScroll_.Unit.Editor, + value: 1, + revealCursor: false, + select: false + }); + } + }); + class WordCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index f91574dc4cb..d80aaf6042d 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -19,7 +19,7 @@ import { OverviewRulerZone } from 'vs/editor/common/viewModel/overviewZoneManage import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IEditorWhitespace, IViewModel } from 'vs/editor/common/viewModel'; import { InjectedText } from 'vs/editor/common/modelLineProjectionData'; -import { IDiffComputationResult, ILineChange } from 'vs/editor/common/diff/diffComputer'; +import { ILineChange, IDiffComputationResult } from 'vs/editor/common/diff/smartLinesDiffComputer'; import { IDimension } from 'vs/editor/common/core/dimension'; /** @@ -899,10 +899,15 @@ export interface ICodeEditor extends editorCommon.IEditor { getWhitespaces(): IEditorWhitespace[]; /** - * Get the vertical position (top offset) for the line w.r.t. to the first line. + * Get the vertical position (top offset) for the line's top w.r.t. to the first line. */ getTopForLineNumber(lineNumber: number): number; + /** + * Get the vertical position (top offset) for the line's bottom w.r.t. to the first line. + */ + getBottomForLineNumber(lineNumber: number): number; + /** * Get the vertical position (top offset) for the position w.r.t. to the first line. */ @@ -910,9 +915,10 @@ export interface ICodeEditor extends editorCommon.IEditor { /** * Set the model ranges that will be hidden in the view. + * Hidden areas are stored per source. * @internal */ - setHiddenAreas(ranges: IRange[]): void; + setHiddenAreas(ranges: IRange[], source?: unknown): void; /** * Sets the editor aria options, primarily the active descendent. @@ -1221,6 +1227,10 @@ export function getCodeEditor(thing: unknown): ICodeEditor | null { return thing.getModifiedEditor(); } + if (isCompositeEditor(thing) && isCodeEditor(thing.activeCodeEditor)) { + return thing.activeCodeEditor; + } + return null; } diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index cd36e6c200e..4cfc92f8a6e 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -24,7 +24,7 @@ export class PageCoordinates { ) { } public toClientCoordinates(): ClientCoordinates { - return new ClientCoordinates(this.x - dom.StandardWindow.scrollX, this.y - dom.StandardWindow.scrollY); + return new ClientCoordinates(this.x - window.scrollX, this.y - window.scrollY); } } @@ -44,7 +44,7 @@ export class ClientCoordinates { ) { } public toPageCoordinates(): PageCoordinates { - return new PageCoordinates(this.clientX + dom.StandardWindow.scrollX, this.clientY + dom.StandardWindow.scrollY); + return new PageCoordinates(this.clientX + window.scrollX, this.clientY + window.scrollY); } } diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index 93b20f1d2ed..f61142282d3 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -339,8 +339,9 @@ export abstract class EditorAction extends EditorCommand { protected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) { type EditorActionInvokedClassification = { owner: 'alexdima'; - name: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; - id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; + comment: 'An editor action has been invoked.'; + name: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The label of the action that was invoked.' }; + id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier of the action that was invoked.' }; }; type EditorActionInvokedEvent = { name: string; diff --git a/src/vs/editor/browser/services/abstractCodeEditorService.ts b/src/vs/editor/browser/services/abstractCodeEditorService.ts index 761c4eee60f..aaa31ee4ce4 100644 --- a/src/vs/editor/browser/services/abstractCodeEditorService.ts +++ b/src/vs/editor/browser/services/abstractCodeEditorService.ts @@ -5,11 +5,12 @@ import * as dom from 'vs/base/browser/dom'; import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore, Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { LinkedList } from 'vs/base/common/linkedList'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { ICodeEditorOpenHandler, ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IContentDecorationRenderOptions, IDecorationRenderOptions, IThemeDecorationRenderOptions, isThemeColor } from 'vs/editor/common/editorCommon'; import { IModelDecorationOptions, IModelDecorationOverviewRulerOptions, InjectedTextOptions, ITextModel, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; @@ -42,6 +43,7 @@ export abstract class AbstractCodeEditorService extends Disposable implements IC protected _globalStyleSheet: GlobalStyleSheet | null; private readonly _decorationOptionProviders = new Map(); private readonly _editorStyleSheets = new Map(); + private readonly _codeEditorOpenHandlers = new LinkedList(); constructor( @IThemeService private readonly _themeService: IThemeService, @@ -247,7 +249,21 @@ export abstract class AbstractCodeEditorService extends Disposable implements IC } abstract getActiveCodeEditor(): ICodeEditor | null; - abstract openCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; + + async openCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise { + for (const handler of this._codeEditorOpenHandlers) { + const candidate = await handler(input, source, sideBySide); + if (candidate !== null) { + return candidate; + } + } + return null; + } + + registerCodeEditorOpenHandler(handler: ICodeEditorOpenHandler): IDisposable { + const rm = this._codeEditorOpenHandlers.unshift(handler); + return toDisposable(rm); + } } export class ModelTransientSettingWatcher { diff --git a/src/vs/editor/browser/services/bulkEditService.ts b/src/vs/editor/browser/services/bulkEditService.ts index 56500981829..386b1c92880 100644 --- a/src/vs/editor/browser/services/bulkEditService.ts +++ b/src/vs/editor/browser/services/bulkEditService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { TextEdit, WorkspaceEdit, WorkspaceEditMetadata, WorkspaceFileEdit, WorkspaceFileEditOptions, WorkspaceTextEdit } from 'vs/editor/common/languages'; +import { TextEdit, WorkspaceEdit, WorkspaceEditMetadata, IWorkspaceFileEdit, WorkspaceFileEditOptions, IWorkspaceTextEdit } from 'vs/editor/common/languages'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -15,49 +15,77 @@ import { CancellationToken } from 'vs/base/common/cancellation'; export const IBulkEditService = createDecorator('IWorkspaceEditService'); -function isWorkspaceFileEdit(thing: any): thing is WorkspaceFileEdit { - return isObject(thing) && (Boolean((thing).newUri) || Boolean((thing).oldUri)); -} - -function isWorkspaceTextEdit(thing: any): thing is WorkspaceTextEdit { - return isObject(thing) && URI.isUri((thing).resource) && isObject((thing).edit); -} - export class ResourceEdit { protected constructor(readonly metadata?: WorkspaceEditMetadata) { } static convert(edit: WorkspaceEdit): ResourceEdit[] { - return edit.edits.map(edit => { - if (isWorkspaceTextEdit(edit)) { - return new ResourceTextEdit(edit.resource, edit.edit, edit.modelVersionId, edit.metadata); + if (ResourceTextEdit.is(edit)) { + return ResourceTextEdit.lift(edit); } - if (isWorkspaceFileEdit(edit)) { - return new ResourceFileEdit(edit.oldUri, edit.newUri, edit.options, edit.metadata); + + if (ResourceFileEdit.is(edit)) { + return ResourceFileEdit.lift(edit); } throw new Error('Unsupported edit'); }); } } -export class ResourceTextEdit extends ResourceEdit { +export class ResourceTextEdit extends ResourceEdit implements IWorkspaceTextEdit { + + static is(candidate: any): candidate is IWorkspaceTextEdit { + if (candidate instanceof ResourceTextEdit) { + return true; + } + return isObject(candidate) + && URI.isUri((candidate).resource) + && isObject((candidate).textEdit); + } + + static lift(edit: IWorkspaceTextEdit): ResourceTextEdit { + if (edit instanceof ResourceTextEdit) { + return edit; + } else { + return new ResourceTextEdit(edit.resource, edit.textEdit, edit.versionId, edit.metadata); + } + } + constructor( readonly resource: URI, readonly textEdit: TextEdit & { insertAsSnippet?: boolean }, - readonly versionId?: number, + readonly versionId: number | undefined = undefined, metadata?: WorkspaceEditMetadata, ) { super(metadata); } } -export class ResourceFileEdit extends ResourceEdit { +export class ResourceFileEdit extends ResourceEdit implements IWorkspaceFileEdit { + + static is(candidate: any): candidate is IWorkspaceFileEdit { + if (candidate instanceof ResourceFileEdit) { + return true; + } else { + return isObject(candidate) + && (Boolean((candidate).newResource) || Boolean((candidate).oldResource)); + } + } + + static lift(edit: IWorkspaceFileEdit): ResourceFileEdit { + if (edit instanceof ResourceFileEdit) { + return edit; + } else { + return new ResourceFileEdit(edit.oldResource, edit.newResource, edit.options, edit.metadata); + } + } + constructor( readonly oldResource: URI | undefined, readonly newResource: URI | undefined, - readonly options?: WorkspaceFileEditOptions, + readonly options: WorkspaceFileEditOptions = {}, metadata?: WorkspaceEditMetadata ) { super(metadata); @@ -92,5 +120,5 @@ export interface IBulkEditService { setPreviewHandler(handler: IBulkEditPreviewHandler): IDisposable; - apply(edit: ResourceEdit[], options?: IBulkEditOptions): Promise; + apply(edit: ResourceEdit[] | WorkspaceEdit, options?: IBulkEditOptions): Promise; } diff --git a/src/vs/editor/browser/services/codeEditorService.ts b/src/vs/editor/browser/services/codeEditorService.ts index b56596939a8..40d7947efcd 100644 --- a/src/vs/editor/browser/services/codeEditorService.ts +++ b/src/vs/editor/browser/services/codeEditorService.ts @@ -10,6 +10,7 @@ import { IModelDecorationOptions, ITextModel } from 'vs/editor/common/model'; import { ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; +import { IDisposable } from 'vs/base/common/lifecycle'; export const ICodeEditorService = createDecorator('codeEditorService'); @@ -53,4 +54,9 @@ export interface ICodeEditorService { getActiveCodeEditor(): ICodeEditor | null; openCodeEditor(input: ITextResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; + registerCodeEditorOpenHandler(handler: ICodeEditorOpenHandler): IDisposable; +} + +export interface ICodeEditorOpenHandler { + (input: ITextResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; } diff --git a/src/vs/editor/browser/services/editorWorkerService.ts b/src/vs/editor/browser/services/editorWorkerService.ts index be0dbf6cbac..2ca1ded563b 100644 --- a/src/vs/editor/browser/services/editorWorkerService.ts +++ b/src/vs/editor/browser/services/editorWorkerService.ts @@ -10,12 +10,11 @@ import { SimpleWorkerClient, logOnceWebWorkerWarning, IWorkerClient } from 'vs/b import { DefaultWorkerFactory } from 'vs/base/browser/defaultWorkerFactory'; import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; -import { IChange, IDiffComputationResult } from 'vs/editor/common/diff/diffComputer'; import { ITextModel } from 'vs/editor/common/model'; import * as languages from 'vs/editor/common/languages'; import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker'; -import { IEditorWorkerService, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorker'; +import { IDiffComputationResult, IEditorWorkerService, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorker'; import { IModelService } from 'vs/editor/common/services/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; import { regExpFlags } from 'vs/base/common/strings'; @@ -26,6 +25,8 @@ import { canceled } from 'vs/base/common/errors'; import { UnicodeHighlighterOptions } from 'vs/editor/common/services/unicodeTextModelHighlighter'; import { IEditorWorkerHost } from 'vs/editor/common/services/editorWorkerHost'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; +import { IChange } from 'vs/editor/common/diff/smartLinesDiffComputer'; +import { IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider'; /** * Stop syncing a model to the worker if it was not needed for 1 min. @@ -94,8 +95,8 @@ export class EditorWorkerService extends Disposable implements IEditorWorkerServ return this._workerManager.withWorker().then(client => client.computedUnicodeHighlights(uri, options, range)); } - public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise { - return this._workerManager.withWorker().then(client => client.computeDiff(original, modified, ignoreTrimWhitespace, maxComputationTime)); + public computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions): Promise { + return this._workerManager.withWorker().then(client => client.computeDiff(original, modified, options)); } public canComputeDirtyDiff(original: URI, modified: URI): boolean { @@ -491,9 +492,9 @@ export class EditorWorkerClient extends Disposable implements IEditorWorkerClien }); } - public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise { + public computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions): Promise { return this._withSyncedResources([original, modified], /* forceLargeModels */true).then(proxy => { - return proxy.computeDiff(original.toString(), modified.toString(), ignoreTrimWhitespace, maxComputationTime); + return proxy.computeDiff(original.toString(), modified.toString(), options); }); } diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 56870b5170c..8b751e86828 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -163,7 +163,7 @@ export class OpenerService implements IOpenerService { // validate against the original URI that this URI resolves to, if one exists const validationTarget = this._resolvedUriTargets.get(targetURI) ?? target; for (const validator of this._validators) { - if (!(await validator.shouldOpen(validationTarget))) { + if (!(await validator.shouldOpen(validationTarget, options))) { return false; } } diff --git a/src/vs/editor/browser/services/webWorker.ts b/src/vs/editor/browser/services/webWorker.ts index c853e3220ec..b5757c58865 100644 --- a/src/vs/editor/browser/services/webWorker.ts +++ b/src/vs/editor/browser/services/webWorker.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { getAllMethodNames } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import { EditorWorkerClient } from 'vs/editor/browser/services/editorWorkerService'; -import { IModelService } from 'vs/editor/common/services/model'; -import * as types from 'vs/base/common/types'; import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; +import { IModelService } from 'vs/editor/common/services/model'; /** * Create a new web worker that has model syncing capabilities built in. @@ -92,7 +92,7 @@ class MonacoWebWorkerImpl extends EditorWorkerClient implement private _getForeignProxy(): Promise { if (!this._foreignProxy) { this._foreignProxy = this._getProxy().then((proxy) => { - const foreignHostMethods = this._foreignModuleHost ? types.getAllMethodNames(this._foreignModuleHost) : []; + const foreignHostMethods = this._foreignModuleHost ? getAllMethodNames(this._foreignModuleHost) : []; return proxy.loadForeignModule(this._foreignModuleId, this._foreignModuleCreateData, foreignHostMethods).then((foreignMethods) => { this._foreignModuleCreateData = null; diff --git a/src/vs/editor/browser/view/domLineBreaksComputer.ts b/src/vs/editor/browser/view/domLineBreaksComputer.ts index bd281d1e9cb..9b4d8f8459b 100644 --- a/src/vs/editor/browser/view/domLineBreaksComputer.ts +++ b/src/vs/editor/browser/view/domLineBreaksComputer.ts @@ -5,7 +5,7 @@ import { WrappingIndent } from 'vs/editor/common/config/editorOptions'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; -import { createStringBuilder, IStringBuilder } from 'vs/editor/common/core/stringBuilder'; +import { StringBuilder } from 'vs/editor/common/core/stringBuilder'; import { CharCode } from 'vs/base/common/charCode'; import * as strings from 'vs/base/common/strings'; import { applyFontInfo } from 'vs/editor/browser/config/domFontInfo'; @@ -72,7 +72,7 @@ function createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: numbe const containerDomNode = document.createElement('div'); applyFontInfo(containerDomNode, fontInfo); - const sb = createStringBuilder(10000); + const sb = new StringBuilder(10000); const firstNonWhitespaceIndices: number[] = []; const wrappedTextIndentLengths: number[] = []; const renderLineContents: string[] = []; @@ -182,7 +182,7 @@ const enum Constants { SPAN_MODULO_LIMIT = 16384 } -function renderLine(lineContent: string, initialVisibleColumn: number, tabSize: number, width: number, sb: IStringBuilder, wrappingIndentLength: number): [number[], number[]] { +function renderLine(lineContent: string, initialVisibleColumn: number, tabSize: number, width: number, sb: StringBuilder, wrappingIndentLength: number): [number[], number[]] { if (wrappingIndentLength !== 0) { const hangingOffset = String(wrappingIndentLength); diff --git a/src/vs/editor/browser/view/renderingContext.ts b/src/vs/editor/browser/view/renderingContext.ts index bed244ba618..5cb7c840858 100644 --- a/src/vs/editor/browser/view/renderingContext.ts +++ b/src/vs/editor/browser/view/renderingContext.ts @@ -53,8 +53,12 @@ export abstract class RestrictedRenderingContext { return absoluteTop - this.scrollTop; } - public getVerticalOffsetForLineNumber(lineNumber: number): number { - return this._viewLayout.getVerticalOffsetForLineNumber(lineNumber); + public getVerticalOffsetForLineNumber(lineNumber: number, includeViewZones?: boolean): number { + return this._viewLayout.getVerticalOffsetForLineNumber(lineNumber, includeViewZones); + } + + public getVerticalOffsetAfterLineNumber(lineNumber: number, includeViewZones?: boolean): number { + return this._viewLayout.getVerticalOffsetAfterLineNumber(lineNumber, includeViewZones); } public getDecorationsInViewport(): ViewModelDecoration[] { diff --git a/src/vs/editor/browser/view/viewLayer.ts b/src/vs/editor/browser/view/viewLayer.ts index 80a6960fa7c..c866fe5242e 100644 --- a/src/vs/editor/browser/view/viewLayer.ts +++ b/src/vs/editor/browser/view/viewLayer.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; -import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder'; +import { StringBuilder } from 'vs/editor/common/core/stringBuilder'; import * as viewEvents from 'vs/editor/common/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; @@ -20,7 +20,7 @@ export interface IVisibleLine extends ILine { * Return null if the HTML should not be touched. * Return the new HTML otherwise. */ - renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean; + renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: StringBuilder): boolean; /** * Layout the line. @@ -547,7 +547,7 @@ class ViewLayerRenderer { } } - private static readonly _sb = createStringBuilder(100000); + private static readonly _sb = new StringBuilder(100000); private _finishRendering(ctx: IRendererContext, domNodeIsEmpty: boolean, deltaTop: number[]): void { diff --git a/src/vs/editor/browser/view/viewOverlays.ts b/src/vs/editor/browser/view/viewOverlays.ts index 7efe9478a51..99ae7d79ceb 100644 --- a/src/vs/editor/browser/view/viewOverlays.ts +++ b/src/vs/editor/browser/view/viewOverlays.ts @@ -8,7 +8,7 @@ import { applyFontInfo } from 'vs/editor/browser/config/domFontInfo'; import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay'; import { IVisibleLine, IVisibleLinesHost, VisibleLinesCollection } from 'vs/editor/browser/view/viewLayer'; import { ViewPart } from 'vs/editor/browser/view/viewPart'; -import { IStringBuilder } from 'vs/editor/common/core/stringBuilder'; +import { StringBuilder } from 'vs/editor/common/core/stringBuilder'; import { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext'; import { ViewContext } from 'vs/editor/common/viewModel/viewContext'; @@ -175,7 +175,7 @@ export class ViewOverlayLine implements IVisibleLine { this._lineHeight = this._configuration.options.get(EditorOption.lineHeight); } - public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean { + public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: StringBuilder): boolean { let result = ''; for (let i = 0, len = this._dynamicOverlays.length; i < len; i++) { const dynamicOverlay = this._dynamicOverlays[i]; diff --git a/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts b/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts index fc935881a7a..48f52d6d231 100644 --- a/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts +++ b/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts @@ -82,9 +82,10 @@ export class BlockDecorations extends ViewPart { block = this.blocks[count] = createFastDomNode(document.createElement('div')); this.domNode.appendChild(block); } - const top = ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber); - // See https://github.com/microsoft/vscode/pull/152740#discussion_r902661546 - const bottom = ctx.getVerticalOffsetForLineNumber(decoration.range.endLineNumber + 1); + const top = ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, true); + const bottom = decoration.range.isEmpty() + ? ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, false) + : ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, true); block.setClassName('blockDecorations-block ' + decoration.options.blockClassName); block.setLeft(ctx.scrollLeft); diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index 056c24f5c73..f45578d9f15 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -340,7 +340,7 @@ class Widget { const MIN_LIMIT = Math.max(0, domNodePosition.left - width); const MAX_LIMIT = Math.min(domNodePosition.left + domNodePosition.width + width, windowSize.width); - let absoluteLeft = domNodePosition.left + left - dom.StandardWindow.scrollX; + let absoluteLeft = domNodePosition.left + left - window.scrollX; if (absoluteLeft + width > MAX_LIMIT) { const delta = absoluteLeft - (MAX_LIMIT - width); @@ -362,8 +362,8 @@ class Widget { const belowTop = bottomLeft.top + this._lineHeight; const domNodePosition = dom.getDomNodePagePosition(this._viewDomNode.domNode); - const absoluteAboveTop = domNodePosition.top + aboveTop - dom.StandardWindow.scrollY; - const absoluteBelowTop = domNodePosition.top + belowTop - dom.StandardWindow.scrollY; + const absoluteAboveTop = domNodePosition.top + aboveTop - window.scrollY; + const absoluteBelowTop = domNodePosition.top + belowTop - window.scrollY; const windowSize = dom.getClientArea(document.body); const [aboveLeft, absoluteAboveLeft] = this._layoutHorizontalSegmentInPage(windowSize, domNodePosition, topLeft.left - ctx.scrollLeft + this._contentLeft, width); diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index eb777952bbd..f48404054da 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -8,7 +8,7 @@ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import * as platform from 'vs/base/common/platform'; 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 { StringBuilder } from 'vs/editor/common/core/stringBuilder'; import { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration'; import { FloatHorizontalRange, VisibleRanges } from 'vs/editor/browser/view/renderingContext'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; @@ -186,7 +186,7 @@ export class ViewLine implements IVisibleLine { return false; } - public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean { + public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: StringBuilder): boolean { if (this._isMaybeInvalid === false) { // it appears that nothing relevant has changed return false; diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index e0ff5f222c4..805395c190b 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -116,6 +116,10 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, private _horizontalRevealRequest: HorizontalRevealRequest | null; private readonly _lastRenderedData: LastRenderedData; + // Sticky Scroll + private _stickyScrollEnabled: boolean; + private _maxNumberStickyLines: number; + constructor(context: ViewContext, linesContent: FastDomNode) { super(context); this._linesContent = linesContent; @@ -155,6 +159,10 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, this._lastRenderedData = new LastRenderedData(); this._horizontalRevealRequest = null; + + // sticky scroll widget + this._stickyScrollEnabled = options.get(EditorOption.stickyScroll).enabled; + this._maxNumberStickyLines = options.get(EditorOption.stickyScroll).maxLineCount; } public override dispose(): void { @@ -196,6 +204,11 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); this._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle); this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); + + // sticky scroll + this._stickyScrollEnabled = options.get(EditorOption.stickyScroll).enabled; + this._maxNumberStickyLines = options.get(EditorOption.stickyScroll).maxLineCount; + applyFontInfo(this.domNode, fontInfo); this._onOptionsMaybeChanged(); @@ -667,22 +680,30 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, const shouldIgnoreScrollOff = (source === 'mouse' || minimalReveal) && this._cursorSurroundingLinesStyle === 'default'; + let paddingTop: number = 0; + let paddingBottom: number = 0; + if (!shouldIgnoreScrollOff) { const context = Math.min((viewportHeight / this._lineHeight) / 2, this._cursorSurroundingLines); - boxStartY -= context * this._lineHeight; - boxEndY += Math.max(0, (context - 1)) * this._lineHeight; + if (this._stickyScrollEnabled) { + paddingTop = Math.max(context, this._maxNumberStickyLines) * this._lineHeight; + } else { + paddingTop = context * this._lineHeight; + } + paddingBottom = Math.max(0, (context - 1)) * this._lineHeight; } else { if (!minimalReveal) { // Reveal one more line above (this case is hit when dragging) - boxStartY -= this._lineHeight; + paddingTop = this._lineHeight; } } - if (verticalType === viewEvents.VerticalRevealType.Simple || verticalType === viewEvents.VerticalRevealType.Bottom) { // Reveal one line more when the last line would be covered by the scrollbar - arrow down case or revealing a line explicitly at bottom - boxEndY += (minimalReveal ? this._horizontalScrollbarHeight : this._lineHeight); + paddingBottom += (minimalReveal ? this._horizontalScrollbarHeight : this._lineHeight); } + boxStartY -= paddingTop; + boxEndY += paddingBottom; let newScrollTop: number; if (boxEndY - boxStartY > viewportHeight) { @@ -724,8 +745,9 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, private _computeScrollLeftToReveal(horizontalRevealRequest: HorizontalRevealRequest): { scrollLeft: number; maxHorizontalOffset: number } | null { const viewport = this._context.viewLayout.getCurrentViewport(); + const layoutInfo = this._context.configuration.options.get(EditorOption.layoutInfo); const viewportStartX = viewport.left; - const viewportEndX = viewportStartX + viewport.width; + const viewportEndX = viewportStartX + viewport.width - layoutInfo.verticalScrollbarWidth; let boxStartX = Constants.MAX_SAFE_SMALL_INTEGER; let boxEndX = 0; diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index ab06570ed5f..12d68b9b527 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -1021,7 +1021,7 @@ export class Minimap extends ViewPart implements IMinimapModel { } else { visibleRange = new Range(startLineNumber, 1, endLineNumber, this._context.viewModel.getLineMaxColumn(endLineNumber)); } - const decorations = this._context.viewModel.getDecorationsInViewport(visibleRange); + const decorations = this._context.viewModel.getDecorationsInViewport(visibleRange, true); if (this._samplingState) { const result: ViewModelDecoration[] = []; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index f4e8c0d10db..8a49db0edb7 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -368,10 +368,15 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._actions[internalAction.id] = internalAction; }); + const isDropIntoEnabled = () => { + return !this._configuration.options.get(EditorOption.readOnly) + && this._configuration.options.get(EditorOption.dropIntoEditor).enabled; + }; + this._register(new dom.DragAndDropObserver(this._domElement, { onDragEnter: () => undefined, onDragOver: e => { - if (!this._configuration.options.get(EditorOption.enableDropIntoEditor)) { + if (!isDropIntoEnabled()) { return; } @@ -381,7 +386,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } }, onDrop: async e => { - if (!this._configuration.options.get(EditorOption.enableDropIntoEditor)) { + if (!isDropIntoEnabled()) { return; } @@ -603,8 +608,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return CodeEditorWidget._getVerticalOffsetAfterPosition(this._modelData, lineNumber, 1, includeViewZones); } - public setHiddenAreas(ranges: IRange[]): void { - this._modelData?.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r))); + public setHiddenAreas(ranges: IRange[], source?: unknown): void { + this._modelData?.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r)), source); } public getVisibleColumnFromPosition(rawPosition: IPosition): number { @@ -1177,9 +1182,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (!this._modelData || text.length === 0) { return; } - const startPosition = this._modelData.viewModel.getSelection().getStartPosition(); - this._modelData.viewModel.paste(text, pasteOnNewLine, multicursorText, source); - const endPosition = this._modelData.viewModel.getSelection().getStartPosition(); + const viewModel = this._modelData.viewModel; + const startPosition = viewModel.getSelection().getStartPosition(); + viewModel.paste(text, pasteOnNewLine, multicursorText, source); + const endPosition = viewModel.getSelection().getStartPosition(); if (source === 'keyboard') { this._onDidPaste.fire({ range: new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column), diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index ee1a5a107b9..9ca599671d4 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -24,11 +24,10 @@ import { IDiffEditorOptions, EditorLayoutInfo, EditorOption, EditorOptions, Edit 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'; -import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder'; +import { StringBuilder } from 'vs/editor/common/core/stringBuilder'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { OverviewRulerZone } from 'vs/editor/common/viewModel/overviewZoneManager'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; @@ -53,10 +52,12 @@ import { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { ILineBreaksComputer } from 'vs/editor/common/modelLineProjectionData'; -import { IChange, ICharChange, IDiffComputationResult, ILineChange } from 'vs/editor/common/diff/diffComputer'; +import { IChange, ICharChange, IDiffComputationResult, ILineChange } from 'vs/editor/common/diff/smartLinesDiffComputer'; import { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration'; import { IDimension } from 'vs/editor/common/core/dimension'; import { isHighContrast } from 'vs/platform/theme/common/theme'; +import { IDocumentDiffProvider } from 'vs/editor/common/diff/documentDiffProvider'; +import { WorkerBasedDocumentDiffProvider } from 'vs/editor/browser/widget/workerBasedDocumentDiffProvider'; export interface IDiffCodeEditorWidgetOptions { originalEditor?: ICodeEditorWidgetOptions; @@ -221,7 +222,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE private readonly _updateDecorationsRunner: RunOnceScheduler; - private readonly _editorWorkerService: IEditorWorkerService; + private readonly _documentDiffProvider: IDocumentDiffProvider; private readonly _contextKeyService: IContextKeyService; private readonly _instantiationService: IInstantiationService; private readonly _codeEditorService: ICodeEditorService; @@ -235,7 +236,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE options: Readonly, codeEditorWidgetOptions: IDiffCodeEditorWidgetOptions, @IClipboardService clipboardService: IClipboardService, - @IEditorWorkerService editorWorkerService: IEditorWorkerService, @IContextKeyService contextKeyService: IContextKeyService, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @@ -246,7 +246,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE ) { super(); - this._editorWorkerService = editorWorkerService; + this._documentDiffProvider = instantiationService.createInstance(WorkerBasedDocumentDiffProvider); this._codeEditorService = codeEditorService; this._contextKeyService = this._register(contextKeyService.createScoped(domElement)); this._instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this._contextKeyService])); @@ -272,7 +272,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE originalEditable: false, diffCodeLens: false, renderOverviewRuler: true, - diffWordWrap: 'inherit' + diffWordWrap: 'inherit', + diffAlgorithm: 'smart', }); if (typeof options.isInEmbeddedEditor !== 'undefined') { @@ -751,7 +752,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._options = newOptions; const beginUpdateDecorations = (changed.ignoreTrimWhitespace || changed.renderIndicators || changed.renderMarginRevertIcon); - const beginUpdateDecorationsSoon = (this._isVisible && (changed.maxComputationTime || changed.maxFileSize)); + const beginUpdateDecorationsSoon = (this._isVisible && (changed.maxComputationTime || changed.maxFileSize || changed.diffAlgorithm)); if (beginUpdateDecorations) { this._beginUpdateDecorations(); @@ -1111,13 +1112,65 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } this._setState(editorBrowser.DiffEditorState.ComputingDiff); - this._editorWorkerService.computeDiff(currentOriginalModel.uri, currentModifiedModel.uri, this._options.ignoreTrimWhitespace, this._options.maxComputationTime).then((result) => { + this._documentDiffProvider.computeDiff(currentOriginalModel, currentModifiedModel, { + ignoreTrimWhitespace: this._options.ignoreTrimWhitespace, + maxComputationTime: this._options.maxComputationTime, + diffAlgorithm: this._options.diffAlgorithm, + }).then(result => { if (currentToken === this._diffComputationToken && currentOriginalModel === this._originalEditor.getModel() && currentModifiedModel === this._modifiedEditor.getModel() ) { this._setState(editorBrowser.DiffEditorState.DiffComputed); - this._diffComputationResult = result; + this._diffComputationResult = { + identical: result.identical, + quitEarly: result.quitEarly, + changes: result.changes.map(m => { + // TODO don't do this translation, but use the diff result directly + let originalStartLineNumber: number; + let originalEndLineNumber: number; + let modifiedStartLineNumber: number; + let modifiedEndLineNumber: number; + let innerChanges = m.innerChanges; + + if (m.originalRange.isEmpty) { + // Insertion + originalStartLineNumber = m.originalRange.startLineNumber - 1; + originalEndLineNumber = 0; + innerChanges = undefined; + } else { + originalStartLineNumber = m.originalRange.startLineNumber; + originalEndLineNumber = m.originalRange.endLineNumberExclusive - 1; + } + + if (m.modifiedRange.isEmpty) { + // Deletion + modifiedStartLineNumber = m.modifiedRange.startLineNumber - 1; + modifiedEndLineNumber = 0; + innerChanges = undefined; + } else { + modifiedStartLineNumber = m.modifiedRange.startLineNumber; + modifiedEndLineNumber = m.modifiedRange.endLineNumberExclusive - 1; + } + + return { + originalStartLineNumber, + originalEndLineNumber, + modifiedStartLineNumber, + modifiedEndLineNumber, + charChanges: innerChanges?.map(m => ({ + originalStartLineNumber: m.originalRange.startLineNumber, + originalStartColumn: m.originalRange.startColumn, + originalEndLineNumber: m.originalRange.endLineNumber, + originalEndColumn: m.originalRange.endColumn, + modifiedStartLineNumber: m.modifiedRange.startLineNumber, + modifiedStartColumn: m.modifiedRange.startColumn, + modifiedEndLineNumber: m.modifiedRange.endLineNumber, + modifiedEndColumn: m.modifiedRange.endColumn, + })) + }; + }) + }; this._updateDecorationsRunner.schedule(); this._onDidUpdateDiff.fire(); } @@ -1189,7 +1242,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE result.ariaLabel = options.originalAriaLabel; } result.readOnly = !this._options.originalEditable; - result.enableDropIntoEditor = !result.readOnly; + result.dropIntoEditor = { enabled: !result.readOnly }; result.extraEditorClassName = 'original-in-monaco-diff-editor'; return { ...result, @@ -1324,9 +1377,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } private _setStrategy(newStrategy: DiffEditorWidgetStyle): void { - if (this._strategy) { - this._strategy.dispose(); - } + this._strategy?.dispose(); this._strategy = newStrategy; newStrategy.applyColors(this._themeService.getColorTheme()); @@ -2428,7 +2479,7 @@ class InlineViewZonesComputer extends ViewZonesComputer { } const hasCharChanges = (decorations.length > 0); - const sb = createStringBuilder(10000); + const sb = new StringBuilder(10000); let maxCharsPerLine = 0; let renderedLineCount = 0; let viewLineCounts: number[] | null = null; @@ -2546,7 +2597,7 @@ class InlineViewZonesComputer extends ViewZonesComputer { renderControlCharacters: boolean, fontLigatures: string, tabSize: number, - sb: IStringBuilder, + sb: StringBuilder, marginDomNode: HTMLElement ): number { @@ -2657,6 +2708,7 @@ function validateDiffEditorOptions(options: Readonly, defaul diffCodeLens: validateBooleanOption(options.diffCodeLens, defaults.diffCodeLens), renderOverviewRuler: validateBooleanOption(options.renderOverviewRuler, defaults.renderOverviewRuler), diffWordWrap: validateDiffWordWrap(options.diffWordWrap, defaults.diffWordWrap), + diffAlgorithm: validateStringSetOption(options.diffAlgorithm, defaults.diffAlgorithm, ['smart', 'experimental']), }; } @@ -2673,6 +2725,7 @@ function changedDiffEditorOptions(a: ValidDiffEditorBaseOptions, b: ValidDiffEdi diffCodeLens: (a.diffCodeLens !== b.diffCodeLens), renderOverviewRuler: (a.renderOverviewRuler !== b.renderOverviewRuler), diffWordWrap: (a.diffWordWrap !== b.diffWordWrap), + diffAlgorithm: (a.diffAlgorithm !== b.diffAlgorithm), }; } diff --git a/src/vs/editor/browser/widget/diffNavigator.ts b/src/vs/editor/browser/widget/diffNavigator.ts index 525c143d10e..6c4cd6f02e2 100644 --- a/src/vs/editor/browser/widget/diffNavigator.ts +++ b/src/vs/editor/browser/widget/diffNavigator.ts @@ -10,7 +10,7 @@ import * as objects from 'vs/base/common/objects'; import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICursorPositionChangedEvent } from 'vs/editor/common/cursorEvents'; import { Range } from 'vs/editor/common/core/range'; -import { ILineChange } from 'vs/editor/common/diff/diffComputer'; +import { ILineChange } from 'vs/editor/common/diff/smartLinesDiffComputer'; import { ScrollType } from 'vs/editor/common/editorCommon'; diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index 38ae5e81a32..cb0cb1f935b 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -34,7 +34,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { ILanguageIdCodec } from 'vs/editor/common/languages'; import { ILanguageService } from 'vs/editor/common/languages/language'; -import { ILineChange } from 'vs/editor/common/diff/diffComputer'; +import { ILineChange } from 'vs/editor/common/diff/smartLinesDiffComputer'; const DIFF_LINES_PADDING = 3; @@ -846,9 +846,7 @@ class DiffReviewNext extends EditorAction { public run(accessor: ServicesAccessor, editor: ICodeEditor): void { const diffEditor = findFocusedDiffEditor(accessor); - if (diffEditor) { - diffEditor.diffReviewNext(); - } + diffEditor?.diffReviewNext(); } } @@ -869,9 +867,7 @@ class DiffReviewPrev extends EditorAction { public run(accessor: ServicesAccessor, editor: ICodeEditor): void { const diffEditor = findFocusedDiffEditor(accessor); - if (diffEditor) { - diffEditor.diffReviewPrev(); - } + diffEditor?.diffReviewPrev(); } } diff --git a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts index 856c957a875..1d24e5e5887 100644 --- a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts +++ b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts @@ -9,7 +9,6 @@ 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 { ConfigurationChangedEvent, IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; -import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -76,7 +75,6 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget { domElement: HTMLElement, options: Readonly, parentEditor: ICodeEditor, - @IEditorWorkerService editorWorkerService: IEditorWorkerService, @IContextKeyService contextKeyService: IContextKeyService, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @@ -86,7 +84,7 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget { @IClipboardService clipboardService: IClipboardService, @IEditorProgressService editorProgressService: IEditorProgressService, ) { - super(domElement, parentEditor.getRawOptions(), {}, clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, editorProgressService); + super(domElement, parentEditor.getRawOptions(), {}, clipboardService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, editorProgressService); this._parentEditor = parentEditor; this._overwriteOptions = options; diff --git a/src/vs/editor/browser/widget/workerBasedDocumentDiffProvider.ts b/src/vs/editor/browser/widget/workerBasedDocumentDiffProvider.ts new file mode 100644 index 00000000000..a05bdb7224b --- /dev/null +++ b/src/vs/editor/browser/widget/workerBasedDocumentDiffProvider.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LineRange, LineRangeMapping, RangeMapping } from 'vs/editor/common/diff/linesDiffComputer'; +import { Range } from 'vs/editor/common/core/range'; +import { IDocumentDiff, IDocumentDiffProvider, IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; +import { ITextModel } from 'vs/editor/common/model'; + +export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider { + constructor( + @IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService, + ) { + } + + async computeDiff(original: ITextModel, modified: ITextModel, options: IDocumentDiffProviderOptions): Promise { + const result = await this.editorWorkerService.computeDiff(original.uri, modified.uri, options); + if (!result) { + throw new Error('no diff result available'); + } + + // Convert from space efficient JSON data to rich objects. + const diff: IDocumentDiff = { + identical: result.identical, + quitEarly: result.quitEarly, + changes: result.changes.map( + (c) => + new LineRangeMapping( + new LineRange(c[0], c[1]), + new LineRange(c[2], c[3]), + c[4]?.map( + (c) => + new RangeMapping( + new Range(c[0], c[1], c[2], c[3]), + new Range(c[4], c[5], c[6], c[7]) + ) + ) + ) + ), + }; + return diff; + } +} diff --git a/src/vs/editor/common/config/editorConfigurationSchema.ts b/src/vs/editor/common/config/editorConfigurationSchema.ts index 50f727fa7dc..7843b0a1640 100644 --- a/src/vs/editor/common/config/editorConfigurationSchema.ts +++ b/src/vs/editor/common/config/editorConfigurationSchema.ts @@ -24,7 +24,7 @@ const editorConfiguration: IConfigurationNode = { type: 'number', default: EDITOR_MODEL_DEFAULTS.tabSize, minimum: 1, - markdownDescription: nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + markdownDescription: nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when {0} is on.", '`#editor.detectIndentation#`') }, // 'editor.indentSize': { // 'anyOf': [ @@ -43,12 +43,12 @@ const editorConfiguration: IConfigurationNode = { 'editor.insertSpaces': { type: 'boolean', default: EDITOR_MODEL_DEFAULTS.insertSpaces, - markdownDescription: nls.localize('insertSpaces', "Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + markdownDescription: nls.localize('insertSpaces', "Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when {0} is on.", '`#editor.detectIndentation#`') }, 'editor.detectIndentation': { type: 'boolean', default: EDITOR_MODEL_DEFAULTS.detectIndentation, - markdownDescription: nls.localize('detectIndentation', "Controls whether `#editor.tabSize#` and `#editor.insertSpaces#` will be automatically detected when a file is opened based on the file contents.") + markdownDescription: nls.localize('detectIndentation', "Controls whether {0} and {1} will be automatically detected when a file is opened based on the file contents.", '`#editor.tabSize#`', '`#editor.insertSpaces#`') }, 'editor.trimAutoWhitespace': { type: 'boolean', @@ -173,9 +173,18 @@ const editorConfiguration: IConfigurationNode = { markdownEnumDescriptions: [ nls.localize('wordWrap.off', "Lines will never wrap."), nls.localize('wordWrap.on', "Lines will wrap at the viewport width."), - nls.localize('wordWrap.inherit', "Lines will wrap according to the `#editor.wordWrap#` setting."), + nls.localize('wordWrap.inherit', "Lines will wrap according to the {0} setting.", '`#editor.wordWrap#`'), ] - } + }, + 'diffEditor.diffAlgorithm': { + type: 'string', + enum: ['smart', 'experimental'], + default: 'smart', + markdownEnumDescriptions: [ + nls.localize('diffAlgorithm.smart', "Uses the default diffing algorithm."), + nls.localize('diffAlgorithm.experimental', "Uses an experimental diffing algorithm."), + ] + }, } }; diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index bafc557e3e4..6e08c683030 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -169,6 +169,10 @@ export interface IEditorOptions { * Control the behavior and rendering of the scrollbars. */ scrollbar?: IEditorScrollbarOptions; + /** + * Control the behavior of sticky scroll options + */ + stickyScroll?: IEditorStickyScrollOptions; /** * Control the behavior and rendering of the minimap. */ @@ -563,7 +567,7 @@ export interface IEditorOptions { * Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter. * Defaults to 'mouseover'. */ - showFoldingControls?: 'always' | 'mouseover'; + showFoldingControls?: 'always' | 'never' | 'mouseover'; /** * Controls whether clicking on the empty content after a folded line will unfold the line. * Defaults to false. @@ -636,6 +640,10 @@ export interface IEditorOptions { * Controls strikethrough deprecated variables. */ showDeprecated?: boolean; + /** + * Controls whether suggestions allow matches in the middle of the word instead of only at the beginning + */ + matchOnWordStartOnly?: boolean; /** * Control the behavior and rendering of the inline hints. */ @@ -661,11 +669,11 @@ export interface IEditorOptions { bracketPairColorization?: IBracketPairColorizationOptions; /** - * Enables dropping into the editor from an external source. + * Controls dropping into the editor from an external source. * - * This shows a preview of the drop location and triggers an `onDropIntoEditor` event. + * When enabled, this shows a preview of the drop location and triggers an `onDropIntoEditor` event. */ - enableDropIntoEditor?: boolean; + dropIntoEditor?: IDropIntoEditorOptions; } /** @@ -729,6 +737,10 @@ export interface IDiffEditorBaseOptions { * Control the wrapping of the diff editor. */ diffWordWrap?: 'off' | 'on' | 'inherit'; + /** + * Diff Algorithm + */ + diffAlgorithm?: 'smart' | 'experimental'; } /** @@ -876,7 +888,7 @@ function applyUpdate(value: T | undefined, update: T): ApplyUpdateResult { } if (Array.isArray(value) || Array.isArray(update)) { const arrayEquals = Array.isArray(value) && Array.isArray(update) && arrays.equals(value, update); - return new ApplyUpdateResult(update, arrayEquals); + return new ApplyUpdateResult(update, !arrayEquals); } let didChange = false; for (const key in update) { @@ -2331,6 +2343,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption>; + +class EditorStickyScroll extends BaseEditorOption { + + constructor() { + const defaults: EditorStickyScrollOptions = { enabled: false, maxLineCount: 5 }; + super( + EditorOption.stickyScroll, 'stickyScroll', defaults, + { + 'editor.stickyScroll.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('editor.stickyScroll', "Shows the nested current scopes during the scroll at the top of the editor.") + }, + 'editor.stickyScroll.maxLineCount': { + type: 'number', + default: defaults.maxLineCount, + minimum: 1, + maximum: 10, + description: nls.localize('editor.stickyScroll.', "Defines the maximum number of sticky lines to show.") + }, + } + ); + } + + public validate(_input: any): EditorStickyScrollOptions { + if (!_input || typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorStickyScrollOptions; + return { + enabled: boolean(input.enabled, this.defaultValue.enabled), + maxLineCount: EditorIntOption.clampedInt(input.maxLineCount, this.defaultValue.maxLineCount, 1, 10), + }; + } +} + +//#endregion + //#region inlayHints /** @@ -2553,20 +2622,20 @@ class EditorInlayHints extends BaseEditorOption