diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 9050664fcee..47d682f8a8e 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -1,6 +1,6 @@ # Code - OSS Development Container -[![Open in Remote - Containers](https://img.shields.io/static/v1?label=Remote%20-%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) +[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) This repository includes configuration for a development container for working with Code - OSS in a local container or using [GitHub Codespaces](https://github.com/features/codespaces). @@ -8,21 +8,21 @@ This repository includes configuration for a development container for working w ## Quick start - local -If you already have VS Code and Docker installed, you can click the badge above or [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) to get started. Clicking these links will cause VS Code to automatically install the Remote - Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. +If you already have VS Code and Docker installed, you can click the badge above or [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) to get started. Clicking these links will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. 1. Install Docker Desktop or Docker for Linux on your local machine. (See [docs](https://aka.ms/vscode-remote/containers/getting-started) for additional details.) -2. **Important**: Docker needs at least **4 Cores and 8 GB of RAM** to run a full build. If you are on macOS, or are using the old Hyper-V engine for Windows, update these values for Docker Desktop by right-clicking on the Docker status bar item and going to **Preferences/Settings > Resources > Advanced**. +2. **Important**: Docker needs at least **4 Cores and 8 GB of RAM** to run a full build with **9 GB of RAM** being recommended. If you are on macOS, or are using the old Hyper-V engine for Windows, update these values for Docker Desktop by right-clicking on the Docker status bar item and going to **Preferences/Settings > Resources > Advanced**. > **Note:** The [Resource Monitor](https://marketplace.visualstudio.com/items?itemName=mutantdino.resourcemonitor) extension is included in the container so you can keep an eye on CPU/Memory in the status bar. -3. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [Remote - Containers](https://aka.ms/vscode-remote/download/containers) extension. +3. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [Dev Containers](https://aka.ms/vscode-remote/download/containers) extension. - ![Image of Remote - Containers extension](https://microsoft.github.io/vscode-remote-release/images/remote-containers-extn.png) + ![Image of Dev Containers extension](https://microsoft.github.io/vscode-remote-release/images/remote-containers-extn.png) - > **Note:** The Remote - Containers extension requires the Visual Studio Code distribution of Code - OSS. See the [FAQ](https://aka.ms/vscode-remote/faq/license) for details. + > **Note:** The Dev Containers extension requires the Visual Studio Code distribution of Code - OSS. See the [FAQ](https://aka.ms/vscode-remote/faq/license) for details. -4. Press Ctrl/Cmd + Shift + P or F1 and select **Remote-Containers: Clone Repository in Container Volume...**. +4. Press Ctrl/Cmd + Shift + P or F1 and select **Dev Containers: Clone Repository in Container Volume...**. > **Tip:** While you can use your local source tree instead, operations like `yarn install` can be slow on macOS or when using the Hyper-V engine on Windows. We recommend the "clone repository in container" approach instead since it uses "named volume" rather than the local filesystem. diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3e40ce61f95..63b61fb7a10 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,9 +6,18 @@ "overrideCommand": false, "runArgs": [ "--init", "--security-opt", "seccomp=unconfined", "--shm-size=1g"], - "settings": { - "resmon.show.battery": false, - "resmon.show.cpufreq": false + // VS Code extensions and settings + "customizations": { + "vscode": { + "settings": { + "resmon.show.battery": false, + "resmon.show.cpufreq": false + }, + "extensions": [ + "dbaeumer.vscode-eslint", + "mutantdino.resourcemonitor" + ] + } }, // noVNC, VNC @@ -24,17 +33,12 @@ } }, - "extensions": [ - "dbaeumer.vscode-eslint", - "mutantdino.resourcemonitor" - ], - // Optionally loads a cached yarn install for the repo "postCreateCommand": ".devcontainer/cache/restore-diff.sh", "remoteUser": "node", "hostRequirements": { - "memory": "8gb" + "memory": "9gb" } } diff --git a/.eslintignore b/.eslintignore index 1c49d5b8846..af5f9a4940b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,6 +6,7 @@ **/extensions/css-language-features/server/test/pathCompletionFixtures/** **/extensions/html-language-features/server/lib/jquery.d.ts **/extensions/html-language-features/server/src/test/pathCompletionFixtures/** +**/extensions/ipynb/notebook-out/** **/extensions/markdown-language-features/media/** **/extensions/markdown-language-features/notebook-out/** **/extensions/markdown-math/notebook-out/** @@ -25,10 +26,7 @@ **/src/typings/**/*.d.ts **/src/vs/*/**/*.d.ts **/src/vs/base/test/common/filters.perf.data.js -**/src/vs/css.build.js -**/src/vs/css.js **/src/vs/loader.js -**/src/vs/nls.build.js -**/src/vs/nls.js **/test/unit/assert.js +**/test/automation/out/** **/typings/** 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 99% rename from build/lib/eslint/code-no-look-behind-regex.ts rename to .eslintplugin/code-no-look-behind-regex.ts index ef3959e39c6..800b59b6479 100644 --- a/build/lib/eslint/code-no-look-behind-regex.ts +++ b/.eslintplugin/code-no-look-behind-regex.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as eslint from 'eslint'; import { TSESTree } from '@typescript-eslint/experimental-utils'; import * as ESTree from 'estree'; 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 98% rename from build/lib/eslint/code-no-unexternalized-strings.ts rename to .eslintplugin/code-no-unexternalized-strings.ts index 056a99868ea..d0c30527f7c 100644 --- a/build/lib/eslint/code-no-unexternalized-strings.ts +++ b/.eslintplugin/code-no-unexternalized-strings.ts @@ -51,7 +51,7 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule { key = keyNode.value; } else if (keyNode.type === AST_NODE_TYPES.ObjectExpression) { - for (let property of keyNode.properties) { + for (const property of keyNode.properties) { if (property.type === AST_NODE_TYPES.Property && !property.computed) { if (property.key.type === AST_NODE_TYPES.Identifier && property.key.name === 'key') { if (isStringLiteral(property.value)) { @@ -97,7 +97,7 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule { // (2) // report all invalid NLS keys if (!key.match(NoUnexternalizedStrings._rNlsKeys)) { - for (let value of values) { + for (const value of values) { context.report({ loc: value.call.loc, messageId: 'badKey', data: { key } }); } } diff --git a/build/lib/eslint/code-no-unused-expressions.ts b/.eslintplugin/code-no-unused-expressions.ts similarity index 99% rename from build/lib/eslint/code-no-unused-expressions.ts rename to .eslintplugin/code-no-unused-expressions.ts index f5f0728836e..450365de2c6 100644 --- a/build/lib/eslint/code-no-unused-expressions.ts +++ b/.eslintplugin/code-no-unused-expressions.ts @@ -11,8 +11,6 @@ * @author Michael Ficarra */ -'use strict'; - import * as eslint from 'eslint'; import { TSESTree } from '@typescript-eslint/experimental-utils'; import * as ESTree from 'estree'; 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 94% rename from build/lib/eslint/vscode-dts-cancellation.ts rename to .eslintplugin/vscode-dts-cancellation.ts index 66f184214b9..6e253a898ca 100644 --- a/build/lib/eslint/vscode-dts-cancellation.ts +++ b/.eslintplugin/vscode-dts-cancellation.ts @@ -20,7 +20,7 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule { ['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature[key.name=/^(provide|resolve).+/]']: (node: any) => { let found = false; - for (let param of (node).params) { + for (const param of (node).params) { if (param.type === AST_NODE_TYPES.Identifier) { found = found || param.name === 'token'; } 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 da169cdcc0c..9b8f2c61094 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,12 +8,19 @@ "plugins": [ "@typescript-eslint", "jsdoc", - "header" + "header", + "local" ], "rules": { "constructor-super": "warn", "curly": "warn", "eqeqeq": "warn", + "prefer-const": [ + "warn", + { + "destructuring": "all" + } + ], "no-buffer-constructor": "warn", "no-caller": "warn", "no-case-declarations": "warn", @@ -55,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": [], @@ -116,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" } }, { @@ -126,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": [ @@ -148,7 +155,7 @@ ] } ], - "vscode-dts-event-naming": [ + "local/vscode-dts-event-naming": [ "warn", { "allowed": [ @@ -194,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: @@ -214,13 +221,11 @@ // - electron-main "when": "hasNode", "allow": [ - "@microsoft/applicationinsights-web", "@parcel/watcher", "@vscode/sqlite3", "@vscode/vscode-languagedetection", "@vscode/ripgrep", "@vscode/iconv-lite-umd", - "applicationinsights", "assert", "child_process", "console", @@ -255,6 +260,7 @@ "windows-process-tree", "worker_threads", "xterm", + "xterm-addon-canvas", "xterm-addon-search", "xterm-addon-serialize", "xterm-addon-unicode11", @@ -269,6 +275,7 @@ // imports that are allowed in all /test/ files "when": "test", "allow": [ + "vs/css.build", "assert", "sinon", "sinon-test" @@ -323,7 +330,9 @@ "vs/base/~", "vs/base/parts/*/~", "vs/platform/*/~", - "tas-client-umd" // node module allowed even in /common/ + "tas-client-umd", // node module allowed even in /common/ + "@microsoft/1ds-core-js",// node module allowed even in /common/ + "@microsoft/1ds-post-js" // node module allowed even in /common/ ] }, { @@ -437,8 +446,7 @@ }, // TODO@layers "tas-client-umd", // node module allowed even in /common/ "vscode-textmate", // node module allowed even in /common/ - "@vscode/vscode-languagedetection", // node module allowed even in /common/ - "@microsoft/applicationinsights-web" // node module allowed even in /common/ + "@vscode/vscode-languagedetection" // node module allowed even in /common/ ] }, { @@ -479,6 +487,14 @@ { "when": "hasBrowser", "pattern": "vs/workbench/workbench.web.main" + }, + { + "when": "hasBrowser", + "pattern": "vs/workbench/~" + }, + { + "when": "hasBrowser", + "pattern": "vs/workbench/services/*/~" } ] }, @@ -529,7 +545,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/*/~", @@ -542,26 +558,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" ] }, { @@ -569,7 +566,7 @@ "restrictions": [] }, { - "target": "src/vs/{css.d.ts,monaco.d.ts,nls.d.ts,nls.mock.ts}", + "target": "src/vs/{loader.d.ts,css.ts,css.build.ts,monaco.d.ts,nls.ts,nls.build.ts,nls.mock.ts}", "restrictions": [] }, { @@ -588,7 +585,7 @@ "test/**/*.ts" ], "rules": { - "code-import-patterns": [ + "local/code-import-patterns": [ "warn", { "target": "test/smoke/**", diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8a44ce8c7ac..ce9e17c1c96 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -13,10 +13,10 @@ Does this issue occur when all extensions are disabled?: Yes/No -- VS Code Version: -- OS Version: +- VS Code Version: +- OS Version: Steps to Reproduce: -1. -2. +1. +2. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 51e7f366043..35dab07012c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,3 +3,6 @@ contact_links: - name: Question url: https://stackoverflow.com/questions/tagged/visual-studio-code about: Please ask and answer questions here. + - name: Extension Development + url: https://github.com/microsoft/vscode-discussions/discussions/5 + about: Please use this for extension development questions and ideas. diff --git a/.github/classifier.json b/.github/classifier.json index 5b5625f6e93..ca0e4f86467 100644 --- a/.github/classifier.json +++ b/.github/classifier.json @@ -1,6 +1,6 @@ { - "$schema": "https://raw.githubusercontent.com/microsoft/vscode-github-triage-actions/master/classifier-deep/apply/apply-labels/deep-classifier-config.schema.json", - "vacation": ["RMacfarlane", "eamodio"], + "$schema": "https://raw.githubusercontent.com/microsoft/vscode-github-triage-actions/stable/classifier-deep/apply/apply-labels/deep-classifier-config.schema.json", + "vacation": [], "assignees": { "nameToOverrideAccuracyOf": {"accuracy": 0.8} }, @@ -18,12 +18,12 @@ "callhierarchy": {"assign": ["jrieken"]}, "code-lens": {"assign": ["jrieken"]}, "color-palette": {"assign": []}, - "comments": {"assign": ["rebornix"]}, + "comments": {"assign": ["alexr00"]}, "config": {"assign": ["sandy081"]}, "context-keys": {"assign": []}, "css-less-scss": {"assign": ["aeschli"]}, "custom-editors": {"assign": ["mjbvz"]}, - "debug": {"assign": ["weinand"]}, + "debug": {"assign": ["roblourens"]}, "dialogs": {"assign": ["sbatten"]}, "diff-editor": {"assign": ["alexdima"]}, "dropdown": {"assign": []}, @@ -58,6 +58,7 @@ "editor-scrollbar": {"assign": ["alexdima"]}, "editor-symbols": {"assign": ["jrieken"]}, "editor-synced-region": {"assign": ["aeschli"]}, + "editor-sticky-scroll": {"assign": ["jrieken"]}, "editor-textbuffer": {"assign": ["alexdima", "rebornix"]}, "editor-theming": {"assign": ["alexdima"]}, "editor-wordnav": {"assign": ["alexdima"]}, @@ -85,7 +86,7 @@ "html": {"assign": ["aeschli"]}, "i18n": {"assign": []}, "icon-brand": {"assign": []}, - "icons-product": {"assign": ["misolori"]}, + "icons-product": {"assign": ["daviddossett"]}, "inlay-hints": {"assign": ["jrieken", "hediet"]}, "inline-completions": {"assign": ["hediet"]}, "install-update": {"assign": []}, @@ -132,7 +133,7 @@ "rename": {"assign": ["jrieken"]}, "scm": {"assign": ["lszomoru"]}, "screencast-mode": {"assign": ["lszomoru"]}, - "search": {"assign": ["roblourens"]}, + "search": {"assign": ["roblourens", "andreamah"]}, "search-editor": {"assign": ["roblourens"]}, "search-replace": {"assign": ["sandy081"]}, "semantic-tokens": {"assign": ["alexdima", "aeschli"]}, @@ -145,7 +146,7 @@ "snippets": {"assign": ["jrieken"]}, "splitview": {"assign": ["joaomoreno"]}, "suggest": {"assign": ["jrieken"]}, - "tasks": {"assign": ["alexr00"], "accuracy": 0.85}, + "tasks": {"assign": ["meganrogge"], "accuracy": 0.85}, "telemetry": {"assign": []}, "themes": {"assign": ["aeschli"]}, "timeline": {"assign": ["lramos15"]}, @@ -158,7 +159,7 @@ "undo-redo": {"assign": ["alexdima"]}, "unit-test": {"assign": []}, "uri": {"assign": ["jrieken"]}, - "ux": {"assign": ["misolori"]}, + "ux": {"assign": ["daviddossett"]}, "variable-resolving": {"assign": []}, "vscode-build": {"assign": []}, "web": {"assign": []}, diff --git a/.github/commands.json b/.github/commands.json index 68a50baae95..5ade58ab38a 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,29 +74,16 @@ "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!" }, - { - "type": "label", - "name": "notebook", - "regex": "notebook.*", - "assign": [ - "rebornix" - ] - }, - { - "type": "label", - "name": "notebook-triage", - "regex": "notebook.*", - "action": "updateLabels", - "addLabel": "notebook-triage" - }, { "type": "label", "name": "L10N", @@ -104,6 +108,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 +159,7 @@ "IllusionMH" ], "action": "updateLabels", - "addLabel": "~needs more info" + "addLabel": "~info-needed" }, { "type": "comment", @@ -165,14 +170,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 +190,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 +228,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 +241,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 +255,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 +269,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 +283,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 +297,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 +311,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 +325,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 +339,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 +366,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 +380,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 +394,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 +408,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 +422,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 +450,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 +473,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/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..5ace4600a1f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" 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/bad-tag.yml b/.github/workflows/bad-tag.yml index e996639dfbd..ba4e0524ccc 100644 --- a/.github/workflows/bad-tag.yml +++ b/.github/workflows/bad-tag.yml @@ -8,7 +8,7 @@ jobs: if: github.event.ref == '1.999.0' steps: - name: Checkout Actions - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: "microsoft/vscode-github-triage-actions" ref: stable diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 0d94b83350a..12e802e9c74 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -1,12 +1,14 @@ name: Basic checks -on: - push: - branches: - - main - pull_request: - branches: - - main +on: workflow_dispatch + +# on: +# push: +# branches: +# - main +# pull_request: +# branches: +# - main jobs: main: @@ -22,8 +24,6 @@ jobs: # TODO: rename azure-pipelines/linux/xvfb.init to github-actions - name: Setup Build Environment run: | - 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 @@ -41,8 +41,7 @@ jobs: uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules21-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules21- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} @@ -62,10 +61,7 @@ jobs: run: yarn --frozen-lockfile --network-timeout 180000 - name: Compile and Download - run: yarn npm-run-all --max_old_space_size=4095 -lp compile "electron x64" playwright-install download-builtin-extensions - - - name: Compile Integration Tests - run: yarn --cwd test/integration/browser compile + run: yarn npm-run-all --max_old_space_size=4095 -lp compile "electron x64" - name: Run Unit Tests id: electron-unit-tests @@ -97,8 +93,7 @@ jobs: uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules21-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules21- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} @@ -117,9 +112,6 @@ jobs: ELECTRON_SKIP_BINARY_DOWNLOAD: 1 run: yarn --frozen-lockfile --network-timeout 180000 - - name: Download Playwright - run: yarn playwright-install - - name: Run Hygiene Checks run: yarn gulp hygiene @@ -163,8 +155,7 @@ jobs: uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules21-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules21- + 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 a9317a9e382..fbc0876623d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: run: echo "::set-output name=value::$(node build/azure-pipelines/common/computeNodeModulesCacheKey.js)" - name: Cache node_modules archive id: cacheNodeModules - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ".build/node_modules_cache" key: "${{ runner.os }}-cacheNodeModulesArchive-${{ steps.nodeModulesCacheKey.outputs.value }}" @@ -49,7 +49,7 @@ jobs: run: echo "::set-output name=dir::$(yarn cache dir)" - name: Cache yarn directory if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.yarnCacheDirPath.outputs.dir }} key: ${{ runner.os }}-yarnCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }} @@ -122,18 +122,17 @@ jobs: run: echo "::set-output name=value::$(node build/azure-pipelines/common/computeNodeModulesCacheKey.js)" - name: Cache node modules id: cacheNodeModules - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules21-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules21- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} run: echo "::set-output name=dir::$(yarn cache dir)" - name: Cache yarn directory if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.yarnCacheDirPath.outputs.dir }} key: ${{ runner.os }}-yarnCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }} @@ -194,18 +193,17 @@ jobs: run: echo "::set-output name=value::$(node build/azure-pipelines/common/computeNodeModulesCacheKey.js)" - name: Cache node modules id: cacheNodeModules - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules21-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules21- + key: ${{ runner.os }}-cacheNodeModulesMacOS-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} run: echo "::set-output name=dir::$(yarn cache dir)" - name: Cache yarn directory if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.yarnCacheDirPath.outputs.dir }} key: ${{ runner.os }}-yarnCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }} @@ -268,18 +266,17 @@ jobs: run: echo "::set-output name=value::$(node build/azure-pipelines/common/computeNodeModulesCacheKey.js)" - name: Cache node modules id: cacheNodeModules - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: "**/node_modules" - key: ${{ runner.os }}-cacheNodeModules21-${{ steps.nodeModulesCacheKey.outputs.value }} - restore-keys: ${{ runner.os }}-cacheNodeModules21- + key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }} - name: Get yarn cache directory path id: yarnCacheDirPath if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} run: echo "::set-output name=dir::$(yarn cache dir)" - name: Cache yarn directory if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.yarnCacheDirPath.outputs.dir }} key: ${{ runner.os }}-yarnCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }} 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/devcontainer-cache.yml b/.github/workflows/devcontainer-cache.yml index db9b3fa7866..b1b4c53b77b 100644 --- a/.github/workflows/devcontainer-cache.yml +++ b/.github/workflows/devcontainer-cache.yml @@ -23,7 +23,7 @@ jobs: - name: Azure CLI login id: az_login - uses: azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a + uses: azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 with: creds: ${{ secrets.AZ_ACR_CREDS }} 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/monaco-editor.yml b/.github/workflows/monaco-editor.yml index e52713a3e99..ba7c85809f5 100644 --- a/.github/workflows/monaco-editor.yml +++ b/.github/workflows/monaco-editor.yml @@ -29,7 +29,7 @@ jobs: run: echo "::set-output name=value::$(node build/azure-pipelines/common/computeNodeModulesCacheKey.js)" - name: Cache node modules id: cacheNodeModules - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: "**/node_modules" key: ${{ runner.os }}-cacheNodeModules20-${{ steps.nodeModulesCacheKey.outputs.value }} @@ -40,7 +40,7 @@ jobs: run: echo "::set-output name=dir::$(yarn cache dir)" - name: Cache yarn directory if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.yarnCacheDirPath.outputs.dir }} key: ${{ runner.os }}-yarnCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }} 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/no-yarn-lock-changes.yml b/.github/workflows/no-yarn-lock-changes.yml index ebd735bf7e5..300a98ad998 100644 --- a/.github/workflows/no-yarn-lock-changes.yml +++ b/.github/workflows/no-yarn-lock-changes.yml @@ -18,8 +18,9 @@ jobs: run: | echo "user: ${{ github.event.pull_request.user.login }}" echo "role: ${{ fromJson(steps.get_permissions.outputs.data).permission }}" + echo "is dependabot: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}" echo "should_run: ${{ !contains(fromJson('["admin", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) }}" - echo "::set-output name=should_run::${{ !contains(fromJson('["admin", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) }}" + echo "::set-output name=should_run::${{ !contains(fromJson('["admin", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) && github.event.pull_request.user.login != 'dependabot[bot]' }}" - name: Get file changes uses: trilom/file-changes-action@ce38c8ce2459ca3c303415eec8cb0409857b4272 if: ${{ steps.control.outputs.should_run == 'true' }} 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/pr-chat.yml b/.github/workflows/pr-chat.yml index 13803fda778..0acad98dc13 100644 --- a/.github/workflows/pr-chat.yml +++ b/.github/workflows/pr-chat.yml @@ -9,7 +9,7 @@ jobs: if: ${{ !github.event.pull_request.draft }} steps: - name: Checkout Actions - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: "microsoft/vscode-github-triage-actions" ref: stable @@ -21,5 +21,6 @@ jobs: with: token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} slack_token: ${{ secrets.SLACK_TOKEN }} + slack_user_token: ${{ secrets.SLACK_USER_TOKEN }} slack_bot_name: "VSCodeBot" notification_channel: codereview diff --git a/.github/workflows/rich-navigation.yml b/.github/workflows/rich-navigation.yml index da11ba22759..dd92342ef3a 100644 --- a/.github/workflows/rich-navigation.yml +++ b/.github/workflows/rich-navigation.yml @@ -14,7 +14,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: caching-stage name: Cache VS Code dependencies with: diff --git a/.github/workflows/telemetry.yml b/.github/workflows/telemetry.yml new file mode 100644 index 00000000000..83e511eeb94 --- /dev/null +++ b/.github/workflows/telemetry.yml @@ -0,0 +1,17 @@ +name: 'Telemetry' +on: + pull_request: +jobs: + check-metdata: + name: 'Check metadata' + runs-on: 'ubuntu-latest' + + steps: + - uses: 'actions/checkout@v3' + + - uses: 'actions/setup-node@v3' + with: + node-version: 'lts/*' + + - name: 'Run vscode-telemetry-extractor' + run: 'npx --package=@vscode/telemetry-extractor --yes vscode-telemetry-extractor -s .' 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/.gitignore b/.gitignore index 738d6793fa9..c338e141c8d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ yarn-error.log vscode.lsif vscode.db /.profile-oss +/cli/target 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/cglicenses.schema.json b/.vscode/cglicenses.schema.json index 8c0ee740102..8131a35217a 100644 --- a/.vscode/cglicenses.schema.json +++ b/.vscode/cglicenses.schema.json @@ -55,6 +55,31 @@ } } } + }, + { + "type": "object", + "required": [ + "name", + "fullLicenseTextUri" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the dependency" + }, + "fullLicenseTextUri": { + "type": "string", + "description": "The URI to the license text of this repository", + "format": "uri" + }, + "prependLicenseText": { + "type": "array", + "description": "A piece of text to prepend to the auto-detected license text of the dependency", + "items": { + "type": "string" + } + } + } } ] } diff --git a/.vscode/cgmanifest.schema.json b/.vscode/cgmanifest.schema.json deleted file mode 100644 index 2e719b02396..00000000000 --- a/.vscode/cgmanifest.schema.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "type": "object", - "properties": { - "registrations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "component": { - "oneOf": [ - { - "type": "object", - "required": [ - "type", - "git" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "git" - ] - }, - "git": { - "type": "object", - "required": [ - "name", - "repositoryUrl", - "commitHash" - ], - "properties": { - "name": { - "type": "string" - }, - "repositoryUrl": { - "type": "string" - }, - "commitHash": { - "type": "string" - } - } - } - } - }, - { - "type": "object", - "required": [ - "type", - "npm" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "npm" - ] - }, - "npm": { - "type": "object", - "required": [ - "name", - "version" - ], - "properties": { - "name": { - "type": "string" - }, - "version": { - "type": "string" - } - } - } - } - }, - { - "type": "object", - "required": [ - "type", - "other" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "other" - ] - }, - "other": { - "type": "object", - "required": [ - "name", - "downloadUrl", - "version" - ], - "properties": { - "name": { - "type": "string" - }, - "downloadUrl": { - "type": "string" - }, - "version": { - "type": "string" - } - } - } - } - } - ] - }, - "repositoryUrl": { - "type": "string", - "description": "The git url of the component" - }, - "version": { - "type": "string", - "description": "The version of the component" - }, - "license": { - "type": "string", - "description": "The name of the license" - }, - "developmentDependency": { - "type": "boolean", - "description": "This component is inlined in the vscode repo and **is not shipped**." - }, - "isOnlyProductionDependency": { - "type": "boolean", - "description": "This component is shipped and **is not inlined in the vscode repo**." - }, - "licenseDetail": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The license text" - } - } - } - } - } -} diff --git a/.vscode/launch.json b/.vscode/launch.json index dd295c02db4..3bf8c67198f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,11 +16,7 @@ "request": "attach", "restart": true, "name": "Attach to Extension Host", - // set to a large number: if there is an issue we're debugging that keeps - // the extension host from coming up, or the renderer is paused/crashes - // before it happens, developers will get an annoying alert, e.g. #126826. - // This can be set to 0 in 1.59. - "timeout": 999999999, + "timeout": 0, "port": 5870, "outFiles": [ "${workspaceFolder}/out/**/*.js", @@ -28,12 +24,12 @@ ] }, { - "type": "pwa-chrome", + "type": "chrome", "request": "attach", "name": "Attach to Shared Process", "timeout": 30000, "port": 9222, - "urlFilter": "*sharedProcess.html*", + "urlFilter": "*sharedProcess*.html*", "presentation": { "hidden": true } @@ -71,6 +67,7 @@ "name": "Attach to Main Process", "timeout": 30000, "port": 5875, + "continueOnAttach": true, "outFiles": [ "${workspaceFolder}/out/**/*.js" ], @@ -96,6 +93,23 @@ "order": 6 } }, + { + "type": "extensionHost", + "request": "launch", + "name": "VS Code Configuration Editing Tests", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/extensions/configuration-editing", + "--extensionTestsPath=${workspaceFolder}/extensions/configuration-editing/out/test" + ], + "outFiles": [ + "${workspaceFolder}/out/**/*.js" + ], + "presentation": { + "group": "5_tests", + "order": 6 + } + }, { "type": "extensionHost", "request": "launch", @@ -189,25 +203,7 @@ } }, { - "type": "extensionHost", - "request": "launch", - "name": "VS Code Custom Editor Tests", - "runtimeExecutable": "${execPath}", - "args": [ - "${workspaceFolder}/extensions/vscode-custom-editor-tests/test-workspace", - "--extensionDevelopmentPath=${workspaceFolder}/extensions/vscode-custom-editor-tests", - "--extensionTestsPath=${workspaceFolder}/extensions/vscode-custom-editor-tests/out/test" - ], - "outFiles": [ - "${workspaceFolder}/out/**/*.js" - ], - "presentation": { - "group": "5_tests", - "order": 6 - } - }, - { - "type": "pwa-chrome", + "type": "chrome", "request": "attach", "name": "Attach to VS Code", "browserAttachLocation": "workspace", @@ -221,7 +217,7 @@ "perScriptSourcemaps": "yes" }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Launch VS Code Internal", "windows": { @@ -234,16 +230,17 @@ "runtimeExecutable": "${workspaceFolder}/scripts/code.sh" }, "port": 9222, - "timeout": 20000, + "timeout": 0, "env": { "VSCODE_EXTHOST_WILL_SEND_SOCKET": null, "VSCODE_SKIP_PRELAUNCH": "1" }, "cleanUp": "wholeBrowser", - "urlFilter": "*workbench.html*", + "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 "--disable-features=CalculateNativeWinOcclusion", ], @@ -262,7 +259,7 @@ } }, { - "type": "pwa-node", + "type": "node", "request": "launch", "name": "VS Code Server (Web)", "runtimeExecutable": "${workspaceFolder}/scripts/code-server.sh", @@ -278,7 +275,7 @@ } }, { - "type": "pwa-node", + "type": "node", "request": "launch", "name": "Main Process", "attachSimplePort": 5875, @@ -299,7 +296,7 @@ } }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "outFiles": [], "perScriptSourcemaps": "yes", @@ -312,7 +309,7 @@ } }, { - "type": "pwa-msedge", + "type": "msedge", "request": "launch", "outFiles": [], "perScriptSourcemaps": "yes", @@ -325,6 +322,33 @@ "order": 3 } }, + { + "type": "chrome", + "request": "launch", + "outFiles": [], + "perScriptSourcemaps": "yes", + "name": "VS Code Web (Chrome)", + "url": "http://localhost:8080", + "preLaunchTask": "Run code web", + "presentation": { + "group": "0_vscode", + "order": 3 + } + }, + { + "type": "msedge", + "request": "launch", + "outFiles": [], + "perScriptSourcemaps": "yes", + "name": "VS Code Web (Edge)", + "url": "http://localhost:8080", + "pauseForSourceMap": false, + "preLaunchTask": "Run code web", + "presentation": { + "group": "0_vscode", + "order": 3 + } + }, { "type": "node", "request": "launch", @@ -407,7 +431,7 @@ } }, { - "type": "pwa-node", + "type": "node", "request": "launch", "name": "Run Unit Tests", "program": "${workspaceFolder}/test/unit/electron/index.js", @@ -437,7 +461,7 @@ } }, { - "type": "pwa-node", + "type": "node", "request": "launch", "name": "Run Unit Tests For Current File", "program": "${workspaceFolder}/test/unit/electron/index.js", @@ -472,10 +496,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" @@ -516,9 +539,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": { @@ -527,9 +551,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": { @@ -560,10 +585,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 1b3790c8cc9..9bf483dbbcc 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:\"May 2022\"" + "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"October 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index 48195c79000..82e9dbfbb8b 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\r\n\r\n$MILESTONE=milestone:\"May 2022\"" + "value": "$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 repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\r\n\r\n$MILESTONE=milestone:\"October 2022\"" }, { "kind": 1, @@ -32,7 +32,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS -$MILESTONE is:issue is:closed label:bug label:insiders-released -label:verified -label:*duplicate -label:*as-designed -label:z-author-verified -label:on-testplan" + "value": "$REPOS -$MILESTONE is:issue is:closed reason:completed label:bug label:insiders-released -label:verified -label:*duplicate -label:*as-designed -label:z-author-verified -label:on-testplan" }, { "kind": 1, @@ -42,7 +42,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS -$MILESTONE is:issue is:closed label:feature-request label:insiders-released -label:on-testplan -label:verified -label:*duplicate" + "value": "$REPOS -$MILESTONE is:issue is:closed reason:completed label:feature-request label:insiders-released -label:on-testplan -label:verified -label:*duplicate" }, { "kind": 1, @@ -62,7 +62,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate" + "value": "$REPOS $MILESTONE is:issue is:closed reason:completed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate" }, { "kind": 1, @@ -97,7 +97,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed label:verification-needed -label:verified" + "value": "$REPOS $MILESTONE is:issue is:closed reason:completed label:verification-needed -label:verified" }, { "kind": 1, @@ -112,7 +112,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -label:z-author-verified -label:unreleased" + "value": "$REPOS $MILESTONE is:issue is:closed reason:completed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -label:z-author-verified -label:unreleased" }, { "kind": 1, @@ -122,7 +122,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -label:z-author-verified label:unreleased" + "value": "$REPOS $MILESTONE is:issue is:closed reason:completed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -label:z-author-verified label:unreleased" }, { "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 4ce504b017f..3bfee2f4e4c 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:\"May 2022\"\n\n$MINE=assignee:@me" + "value": "$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 repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\r\n\r\n$MILESTONE=milestone:\"October 2022\"\r\n\r\n$MINE=assignee:@me" }, { "kind": 1, @@ -42,7 +42,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE $MINE is:issue is:closed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate" + "value": "$REPOS $MILESTONE $MINE is:issue is:closed reason:completed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate" }, { "kind": 1, @@ -62,7 +62,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE $MINE is:issue is:closed label:feature-request label:verification-needed -label:verified" + "value": "$REPOS $MILESTONE $MINE is:issue is:closed reason:completed label:feature-request label:verification-needed -label:verified" }, { "kind": 1, @@ -87,7 +87,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed -assignee:@me -label:verified -label:z-author-verified label:feature-request label:verification-needed" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed reason:completed -assignee:@me -label:verified -label:z-author-verified label:feature-request label:verification-needed -label:verification-steps-needed -label:unreleased" }, { "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 reason:completed 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 reason:completed 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, @@ -167,7 +167,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:verification-found" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed reason:completed -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:verification-found" }, { "kind": 1, @@ -177,6 +177,6 @@ { "kind": 2, "language": "github-issues", - "value": "repo:microsoft/vscode $MILESTONE $MINE is:issue is:closed label:feature-request -label:on-release-notes" + "value": "repo:microsoft/vscode $MILESTONE $MINE is:issue is:closed reason:completed label:feature-request -label:on-release-notes" } ] \ No newline at end of file diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index 143697b0c4e..69d50e05965 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:\"May 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 repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\n\n// current milestone name\n$milestone=milestone:\"October 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/notebooks/verification.github-issues b/.vscode/notebooks/verification.github-issues index 7015a401be5..5c6354a4e72 100644 --- a/.vscode/notebooks/verification.github-issues +++ b/.vscode/notebooks/verification.github-issues @@ -2,7 +2,7 @@ { "kind": 1, "language": "markdown", - "value": "### Bug Verification Queries\n\nBefore shipping we want to verify _all_ bugs. That means when a bug is fixed we check that the fix actually works. It's always best to start with bugs that you have filed and the proceed with bugs that have been filed from users outside the development team. " + "value": "### Bug Verification Queries\r\n\r\nBefore shipping we want to verify _all_ bugs. That means when a bug is fixed we check that the fix actually works. It's always best to start with bugs that you have filed and the proceed with bugs that have been filed from users outside the development team. " }, { "kind": 1, @@ -12,7 +12,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev 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-emmet-helper repo:microsoft/vscode-jupyter repo:microsoft/vscode-python\n$milestone=milestone:\"May 2022\"" + "value": "$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 repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\n$milestone=milestone:\"May 2022\"" }, { "kind": 1, @@ -22,7 +22,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate author:@me" + "value": "$repos $milestone is:closed reason:completed -assignee:@me label:bug -label:verified -label:*duplicate author:@me" }, { "kind": 1, @@ -32,7 +32,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate -author:@me -assignee:@me label:bug -label:verified -author:@me -author:aeschli -author:alexdima -author:alexr00 -author:bpasero -author:chrisdias -author:chrmarti -author:connor4312 -author:dbaeumer -author:deepak1556 -author:eamodio -author:egamma -author:gregvanl -author:isidorn -author:JacksonKearl -author:joaomoreno -author:jrieken -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:RMacfarlane -author:roblourens -author:sana-ajani -author:sandy081 -author:sbatten -author:Tyriar -author:weinand -author:rzhao271 -author:kieferrm -author:TylerLeonhardt -author:bamurtaugh -author:hediet -author:joyceerhl -author:rchiodo -author:IanMatthewHuff" + "value": "$repos $milestone is:closed reason:completed -assignee:@me label:bug -label:verified -label:*duplicate -author:@me -assignee:@me label:bug -label:verified -author:@me -author:aeschli -author:alexdima -author:alexr00 -author:bpasero -author:chrisdias -author:chrmarti -author:connor4312 -author:dbaeumer -author:deepak1556 -author:eamodio -author:egamma -author:gregvanl -author:isidorn -author:JacksonKearl -author:joaomoreno -author:jrieken -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:RMacfarlane -author:roblourens -author:sana-ajani -author:sandy081 -author:sbatten -author:Tyriar -author:weinand -author:rzhao271 -author:kieferrm -author:TylerLeonhardt -author:bamurtaugh -author:hediet -author:joyceerhl -author:rchiodo -author:IanMatthewHuff" }, { "kind": 1, @@ -42,6 +42,6 @@ { "kind": 2, "language": "github-issues", - "value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate" + "value": "$repos $milestone is:closed reason:completed -assignee:@me label:bug -label:verified -label:*duplicate" } ] \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index e698d02574e..eea3f45f764 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ ".build": true, ".profile-oss": true, "**/.DS_Store": true, + "cli/target": true, "build/**/*.js": { "when": "$(basename).ts" } @@ -41,11 +42,6 @@ } } ], - "eslint.options": { - "rulePaths": [ - "./build/lib/eslint" - ] - }, "typescript.tsdk": "node_modules/typescript/lib", "npm.exclude": "**/extensions/**", "npm.packageManager": "yarn", @@ -57,7 +53,7 @@ "fileMatch": [ "cgmanifest.json" ], - "url": "./.vscode/cgmanifest.schema.json" + "url": "https://json.schemastore.org/component-detection-manifest.json", }, { "fileMatch": [ @@ -69,10 +65,13 @@ "git.ignoreLimitWarning": true, "git.branchProtection": [ "main", + "distro", "release/*" ], "git.branchProtectionPrompt": "alwaysCommitToNewBranch", "git.branchRandomName.enable": true, + "git.pullBeforeCheckout": true, + "git.mergeEditor": true, "remote.extensionKind": { "msjsdiag.debugger-for-chrome": "workspace" }, @@ -89,6 +88,13 @@ "editor.defaultFormatter": "vscode.typescript-language-features", "editor.formatOnSave": true }, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true, + }, + "rust-analyzer.linkedProjects": [ + "cli/Cargo.toml" + ], "typescript.tsc.autoDetect": "off", "testing.autoRun.mode": "rerun", "conventionalCommits.scopes": [ @@ -101,11 +107,7 @@ "git", "sash" ], - "editor.quickSuggestions": { - "other": "inline", - "comments": "inline", - "strings": "inline" - }, "githubPullRequests.assignCreated": "${user}", - "githubPullRequests.defaultMergeMethod": "squash" + "githubPullRequests.defaultMergeMethod": "squash", + "application.experimental.rendererProfiling": true } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 885f825cc2e..59b1893c293 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -203,6 +203,28 @@ "reveal": "never" } }, + { + "type": "shell", + "command": "./scripts/code-web.sh", + "windows": { + "command": ".\\scripts\\code-web.bat" + }, + "args": ["--port", "8080", "--browser", "none"], + "label": "Run code web", + "isBackground": true, + "problemMatcher": { + "pattern": { + "regexp": "" + }, + "background": { + "beginsPattern": ".*node .*", + "endsPattern": "Listening on .*" + } + }, + "presentation": { + "reveal": "never" + } + }, { "type": "npm", "script": "eslint", diff --git a/.yarnrc b/.yarnrc index 78ab1d5e2b7..f5edf10bc83 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,4 +1,4 @@ disturl "https://electronjs.org/headers" -target "17.4.6" +target "19.0.17" runtime "electron" build_from_source "true" diff --git a/README.md b/README.md index ba8f7224ff7..0c7c6236c42 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. @@ -57,10 +58,10 @@ VS Code includes a set of built-in extensions located in the [extensions](extens ## Development Container -This repository includes a Visual Studio Code Remote - Containers / GitHub Codespaces development container. +This repository includes a Visual Studio Code Dev Containers / GitHub Codespaces development container. -- For [Remote - Containers](https://aka.ms/vscode-remote/download/containers), use the **Remote-Containers: Clone Repository in Container Volume...** command which creates a Docker volume for better disk I/O on macOS and Windows. - - If you already have VS Code and Docker installed, you can also click [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) to get started. This will cause VS Code to automatically install the Remote - Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. +- For [Dev Containers](https://aka.ms/vscode-remote/download/containers), use the **Dev Containers: Clone Repository in Container Volume...** command which creates a Docker volume for better disk I/O on macOS and Windows. + - If you already have VS Code and Docker installed, you can also click [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) to get started. This will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. - For Codespaces, install the [GitHub Codespaces](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces) extension in VS Code, and use the **Codespaces: Create New Codespace** command. Docker / the Codespace should have at least **4 Cores and 6 GB of RAM (8 GB recommended)** to run full build. See the [development container README](.devcontainer/README.md) for more information. diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 0fca6a19272..a48785b38fa 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -1,83 +1,66 @@ -microsoft-vscode +NOTICES -THIRD-PARTY SOFTWARE NOTICES AND INFORMATION -Do Not Translate or Localize - -This project incorporates components from the projects listed below. The original copyright notices and the licenses under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise. - -1. atom/language-clojure version 0.22.8 (https://github.com/atom/language-clojure) -2. atom/language-coffee-script version 0.49.3 (https://github.com/atom/language-coffee-script) -3. atom/language-css version 0.45.0 (https://github.com/atom/language-css) -4. atom/language-java version 0.32.1 (https://github.com/atom/language-java) -5. atom/language-sass version 0.62.1 (https://github.com/atom/language-sass) -6. atom/language-shellscript version 0.28.2 (https://github.com/atom/language-shellscript) -7. atom/language-xml version 0.35.2 (https://github.com/atom/language-xml) -8. better-go-syntax version 1.0.0 (https://github.com/jeff-hykin/better-go-syntax/ ) -9. Colorsublime-Themes version 0.1.0 (https://github.com/Colorsublime/Colorsublime-Themes) -10. daaain/Handlebars version 1.8.0 (https://github.com/daaain/Handlebars) -11. dart-lang/dart-syntax-highlight (https://github.com/dart-lang/dart-syntax-highlight) -12. davidrios/pug-tmbundle (https://github.com/davidrios/pug-tmbundle) -13. definitelytyped (https://github.com/DefinitelyTyped/DefinitelyTyped) -14. demyte/language-cshtml version 0.3.0 (https://github.com/demyte/language-cshtml) -15. Document Object Model version 4.0.0 (https://www.w3.org/DOM/) -16. dompurify version 2.3.1 (https://github.com/cure53/DOMPurify) -17. dotnet/csharp-tmLanguage version 0.1.0 (https://github.com/dotnet/csharp-tmLanguage) -18. expand-abbreviation version 0.5.8 (https://github.com/emmetio/expand-abbreviation) -19. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) -20. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) -21. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) -22. Ikuyadeu/vscode-R version 2.3.8 (https://github.com/Ikuyadeu/vscode-R) -23. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) -24. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) -25. James-Yu/LaTeX-Workshop version 8.19.1 (https://github.com/James-Yu/LaTeX-Workshop) -26. jeff-hykin/cpp-textmate-grammar version 1.12.11 (https://github.com/jeff-hykin/cpp-textmate-grammar) -27. jeff-hykin/cpp-textmate-grammar version 1.15.6 (https://github.com/jeff-hykin/cpp-textmate-grammar) -28. jlelong/vscode-latex-basics version 1.3.0 (https://github.com/jlelong/vscode-latex-basics) -29. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) -30. JuliaEditorSupport/atom-language-julia version 0.22.1 (https://github.com/JuliaEditorSupport/atom-language-julia) -31. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) -32. language-docker (https://github.com/moby/moby) -33. language-less version 0.34.2 (https://github.com/atom/language-less) -34. language-php version 0.48.1 (https://github.com/atom/language-php) -35. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) -36. marked version 4.0.16 (https://github.com/markedjs/marked) -37. mdn-data version 1.1.12 (https://github.com/mdn/data) -38. microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/microsoft/TypeScript-TmLanguage) -39. microsoft/vscode-JSON.tmLanguage (https://github.com/microsoft/vscode-JSON.tmLanguage) -40. microsoft/vscode-markdown-tm-grammar version 1.0.0 (https://github.com/microsoft/vscode-markdown-tm-grammar) -41. microsoft/vscode-mssql version 1.10.1 (https://github.com/microsoft/vscode-mssql) -42. mmims/language-batchfile version 0.7.6 (https://github.com/mmims/language-batchfile) -43. NVIDIA/cuda-cpp-grammar (https://github.com/NVIDIA/cuda-cpp-grammar) -44. PowerShell/EditorSyntax version 1.0.0 (https://github.com/PowerShell/EditorSyntax) -45. rust-syntax version 0.5.0 (https://github.com/dustypomerleau/rust-syntax) -46. semver version 5.5.0 (https://github.com/npm/node-semver) -47. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) -48. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) -49. sumneko/lua.tmbundle version 1.0.0 (https://github.com/sumneko/lua.tmbundle) -50. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) -51. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) -52. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) -53. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) -54. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) -55. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) -56. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) -57. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) -58. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) -59. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) -60. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) -61. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) -62. trond-snekvik/vscode-rst version 1.5.1 (https://github.com/trond-snekvik/vscode-rst) -63. TypeScript-TmLanguage version 0.1.8 (https://github.com/microsoft/TypeScript-TmLanguage) -64. TypeScript-TmLanguage version 1.0.0 (https://github.com/microsoft/TypeScript-TmLanguage) -65. Unicode version 12.0.0 (https://home.unicode.org/) -66. vscode-codicons version 0.0.14 (https://github.com/microsoft/vscode-codicons) -67. vscode-logfile-highlighter version 2.11.0 (https://github.com/emilast/vscode-logfile-highlighter) -68. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) -69. Web Background Synchronization (https://github.com/WICG/background-sync) +This repository incorporates material as listed below or described in the code. -%% atom/language-clojure NOTICES AND INFORMATION BEGIN HERE -========================================= + +--------------------------------------------------------- + +@iktakahiro/markdown-it-katex 4.0.2 - MIT +https://github.com/mjbvz/markdown-it-katex + +The MIT License (MIT) + +Copyright (c) 2016 Waylon Flinn + +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. + +--- + +The MIT License (MIT) + +Copyright (c) 2018 Takahiro Ethan Ikeuchi @iktakahiro + +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. +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-clojure 0.22.8 - MIT +https://github.com/atom/language-clojure + Copyright (c) 2014 GitHub Inc. Permission is hereby granted, free of charge, to any person obtaining @@ -125,11 +108,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF atom/language-clojure NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-coffee-script 0.49.3 - MIT +https://github.com/atom/language-coffee-script -%% atom/language-coffee-script NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -180,11 +165,13 @@ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF atom/language-coffee-script NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-css 0.45.1 - GitHub License +https://github.com/atom/language-css -%% atom/language-css NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) 2014 GitHub Inc. Permission is hereby granted, free of charge, to any person obtaining @@ -216,11 +203,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF atom/language-css NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-java 0.32.1 - MIT +https://github.com/atom/language-java -%% atom/language-java NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -253,11 +242,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF atom/language-java NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-sass 0.62.1 - MIT +https://github.com/atom/language-sass -%% atom/language-sass NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -306,11 +297,13 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF atom/language-sass NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-shellscript 0.28.2 - MIT +https://github.com/atom/language-shellscript -%% atom/language-shellscript NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -343,11 +336,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF atom/language-shellscript NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-xml 0.35.2 - MIT +https://github.com/atom/language-xml -%% atom/language-xml NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -380,11 +375,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF atom/language-xml NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +better-go-syntax 1.0.0 - MIT +https://github.com/jeff-hykin/better-go-syntax/ -%% better-go-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2019 Jeff Hykin @@ -406,11 +403,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF better-go-syntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Colorsublime-Themes 0.1.0 +https://github.com/Colorsublime/Colorsublime-Themes -%% Colorsublime-Themes NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) 2015 Colorsublime.com Permission is hereby granted, free of charge, to any person obtaining a copy @@ -430,11 +429,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF Colorsublime-Themes NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +daaain/Handlebars 1.8.0 - MIT +https://github.com/daaain/Handlebars -%% daaain/Handlebars NOTICES AND INFORMATION BEGIN HERE -========================================= -- Credits Adapted from the great sublime-text-handlebars package by Nicholas Westlake. @@ -452,11 +453,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF daaain/Handlebars NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +dart-lang/dart-syntax-highlight 0.0.0 - BSD +https://github.com/dart-lang/dart-syntax-highlight -%% dart-lang/dart-syntax-highlight NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright 2020, the Dart project authors. Redistribution and use in source and binary forms, with or without @@ -484,11 +487,13 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -========================================= -END OF dart-lang/dart-syntax-highlight NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +davidrios/pug-tmbundle 0.0.0 - MIT +https://github.com/davidrios/pug-tmbundle -%% davidrios/pug-tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2016 David Rios @@ -509,11 +514,13 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF davidrios/pug-tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +definitelytyped - MIT +https://github.com/DefinitelyTyped/DefinitelyTyped -%% definitelytyped NOTICES AND INFORMATION BEGIN HERE -========================================= This project is licensed under the MIT license. Copyrights are respective of each contributor listed at the beginning of each definition file. @@ -522,38 +529,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF definitelytyped NOTICES AND INFORMATION +--------------------------------------------------------- -%% demyte/language-cshtml NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) +--------------------------------------------------------- -Copyright (c) 2014 James Summerton +Document Object Model 4.0.0 - W3C License +https://www.w3.org/DOM/ -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF demyte/language-cshtml NOTICES AND INFORMATION - -%% Document Object Model NOTICES AND INFORMATION BEGIN HERE -========================================= W3C License This work is being provided by the copyright holders under the following license. By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. @@ -570,11 +552,13 @@ FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT W COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. -========================================= -END OF Document Object Model NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +dompurify 2.3.1 - Apache 2.0 +https://github.com/cure53/DOMPurify -%% dompurify NOTICES AND INFORMATION BEGIN HERE -========================================= DOMPurify Copyright 2015 Mario Heiderich @@ -952,11 +936,13 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -========================================= -END OF dompurify NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +dotnet/csharp-tmLanguage 0.1.0 - MIT +https://github.com/dotnet/csharp-tmLanguage -%% dotnet/csharp-tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2016 .NET Foundation @@ -978,11 +964,42 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF dotnet/csharp-tmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +dotnet/razor-tooling 1.0.0 - MIT +https://github.com/dotnet/razor-tooling + +MIT License + +Copyright (c) .NET Foundation and Contributors +All Rights Reserved + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +--------------------------------------------------------- + +--------------------------------------------------------- + +expand-abbreviation 0.5.8 - MIT +https://github.com/emmetio/expand-abbreviation -%% expand-abbreviation NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2017 Emmet.io @@ -1004,11 +1021,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF expand-abbreviation NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +fadeevab/make.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/fadeevab/make.tmbundle -%% fadeevab/make.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-make.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -1022,11 +1041,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF fadeevab/make.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +freebroccolo/atom-language-swift 0.0.0 - MIT +https://github.com/freebroccolo/atom-language-swift -%% freebroccolo/atom-language-swift NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 Darin Morrison @@ -1047,11 +1068,13 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF freebroccolo/atom-language-swift NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +HTML 5.1 W3C Working Draft 08 October 2015 - W3C Document License +http://www.w3.org/TR/2015/WD-html51-20151008/ -%% HTML 5.1 W3C Working Draft NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright Š 2015 W3CÂŽ (MIT, ERCIM, Keio, Beihang). This software or document includes material copied from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.) @@ -1065,11 +1088,13 @@ DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to this document or its contents without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders. -========================================= -END OF HTML 5.1 W3C Working Draft NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Ikuyadeu/vscode-R 2.3.8 - MIT +https://github.com/Ikuyadeu/vscode-R -%% Ikuyadeu/vscode-R NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2022 REditorSupport @@ -1091,11 +1116,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF Ikuyadeu/vscode-R NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Ionic documentation 1.2.4 - Apache2 +https://github.com/ionic-team/ionic-site -%% Ionic documentation NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright Drifty Co. http://drifty.com/. Apache License @@ -1153,11 +1180,13 @@ If the Work includes a "NOTICE" text file as part of its distribution, then any 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS -========================================= -END OF Ionic documentation NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +ionide/ionide-fsgrammar 0.0.0 - MIT +https://github.com/ionide/ionide-fsgrammar -%% ionide/ionide-fsgrammar NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2015 Krzysztof Cieslak @@ -1179,11 +1208,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF ionide/ionide-fsgrammar NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +James-Yu/LaTeX-Workshop 8.19.1 - MIT +https://github.com/James-Yu/LaTeX-Workshop -%% James-Yu/LaTeX-Workshop NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2016 James Yu @@ -1205,11 +1236,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF James-Yu/LaTeX-Workshop NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +jeff-hykin/better-c-syntax 1.13.2 - MIT +https://github.com/jeff-hykin/better-c-syntax -%% jeff-hykin/cpp-textmate-grammar NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2019 Jeff Hykin @@ -1231,11 +1264,97 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF jeff-hykin/cpp-textmate-grammar NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +jeff-hykin/better-cpp-syntax 1.15.23 - MIT +https://github.com/jeff-hykin/better-cpp-syntax + +MIT License + +Copyright (c) 2019 Jeff Hykin + +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. +--------------------------------------------------------- + +--------------------------------------------------------- + +jeff-hykin/better-objc-syntax 0.2.0 - MIT +https://github.com/jeff-hykin/better-objc-syntax + +MIT License + +Copyright (c) 2019 Jeff Hykin + +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. +--------------------------------------------------------- + +--------------------------------------------------------- + +jeff-hykin/better-objcpp-syntax 0.1.0 - MIT +https://github.com/jeff-hykin/better-objcpp-syntax + +MIT License + +Copyright (c) 2019 Jeff Hykin + +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. +--------------------------------------------------------- + +--------------------------------------------------------- + +jlelong/vscode-latex-basics 1.4.0 - MIT +https://github.com/jlelong/vscode-latex-basics -%% jlelong/vscode-latex-basics NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) vscode-latex-basics authors If not otherwise specified (see below), files in this repository fall under the MIT License @@ -1254,11 +1373,13 @@ included in VSCode and falls under the license described in markdown-latex-combi The file syntaxes/cpp-grammar-bailout.tmLanguage.json is generated from https://github.com/jeff-hykin/better-cpp-syntax and falls under the license described in cpp-bailout-license.txt. -========================================= -END OF jlelong/vscode-latex-basics NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +js-beautify 1.6.8 - MIT +https://github.com/beautify-web/js-beautify -%% js-beautify NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. @@ -1268,11 +1389,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF js-beautify NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +JuliaEditorSupport/atom-language-julia 0.22.1 - MIT +https://github.com/JuliaEditorSupport/atom-language-julia -%% JuliaEditorSupport/atom-language-julia NOTICES AND INFORMATION BEGIN HERE -========================================= The atom-language-julia package is licensed under the MIT "Expat" License: > Copyright (c) 2015 @@ -1295,11 +1418,13 @@ The atom-language-julia package is licensed under the MIT "Expat" License: > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF JuliaEditorSupport/atom-language-julia NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Jxck/assert 1.0.0 - MIT +https://github.com/Jxck/assert -%% Jxck/assert NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2011 Jxck @@ -1323,11 +1448,13 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF Jxck/assert NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +language-docker 0.0.0 - Apache2 +https://github.com/moby/moby -%% language-docker NOTICES AND INFORMATION BEGIN HERE -========================================= Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ @@ -1518,11 +1645,13 @@ Apache License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -========================================= -END OF language-docker NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +language-less 0.34.2 - MIT +https://github.com/atom/language-less -%% language-less NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -1570,11 +1699,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF language-less NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +language-php 0.48.1 - MIT +https://github.com/atom/language-php -%% language-php NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -1607,11 +1738,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF language-php NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +MagicStack/MagicPython 1.1.1 - MIT +https://github.com/MagicStack/MagicPython -%% MagicStack/MagicPython NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License Copyright (c) 2015-present MagicStack Inc. http://magic.io @@ -1633,11 +1766,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF MagicStack/MagicPython NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +marked 4.1.0 - MIT +https://github.com/markedjs/marked -%% marked NOTICES AND INFORMATION BEGIN HERE -========================================= information ## Contribution License Agreement @@ -1682,11 +1817,13 @@ Redistribution and use in source and binary forms, with or without modification, * Neither the name "Markdown" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. -========================================= -END OF marked NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +mdn-data 1.1.12 - MPL +https://github.com/mdn/data -%% mdn-data NOTICES AND INFORMATION BEGIN HERE -========================================= Mozilla Public License Version 2.0 Copyright (c) 2018 Mozilla Corporation @@ -2063,11 +2200,13 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -========================================= -END OF mdn-data NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +microsoft/TypeScript-TmLanguage 0.0.1 - MIT +https://github.com/microsoft/TypeScript-TmLanguage -%% microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) Microsoft Corporation All rights reserved. @@ -2090,11 +2229,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +microsoft/vscode-JSON.tmLanguage 0.0.0 - MIT +https://github.com/microsoft/vscode-JSON.tmLanguage -%% microsoft/vscode-JSON.tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= vscode-JSON.tmLanguage Copyright (c) Microsoft Corporation @@ -2114,11 +2255,13 @@ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF microsoft/vscode-JSON.tmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +microsoft/vscode-markdown-tm-grammar 1.0.0 - MIT +https://github.com/microsoft/vscode-markdown-tm-grammar -%% microsoft/vscode-markdown-tm-grammar NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) Microsoft 2018 @@ -2140,11 +2283,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF microsoft/vscode-markdown-tm-grammar NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +microsoft/vscode-mssql 1.16.0 - MIT +https://github.com/microsoft/vscode-mssql -%% microsoft/vscode-mssql NOTICES AND INFORMATION BEGIN HERE -========================================= ------------------------------------------ START OF LICENSE ----------------------------------------- vscode-mssql Copyright (c) Microsoft Corporation @@ -2155,11 +2300,13 @@ Copyright (c) 2016 Microsoft The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------- END OF LICENSE ----------------------------------------- -========================================= -END OF microsoft/vscode-mssql NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +mmims/language-batchfile 0.7.6 - MIT +https://github.com/mmims/language-batchfile -%% mmims/language-batchfile NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2021 Michael Mims @@ -2181,11 +2328,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF mmims/language-batchfile NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +NVIDIA/cuda-cpp-grammar 0.0.0 - MIT +https://github.com/NVIDIA/cuda-cpp-grammar -%% NVIDIA/cuda-cpp-grammar NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright 2021 NVIDIA Corporation @@ -2195,11 +2344,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF NVIDIA/cuda-cpp-grammar NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +PowerShell/EditorSyntax 1.0.0 - MIT +https://github.com/PowerShell/EditorSyntax -%% PowerShell/EditorSyntax NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) Microsoft Corporation All rights reserved. @@ -2223,11 +2374,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF PowerShell/EditorSyntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +rust-syntax 0.5.0 - MIT +https://github.com/dustypomerleau/rust-syntax -%% rust-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2020 Dustin Pomerleau @@ -2249,11 +2402,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF rust-syntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +semver 5.5.0 - The ISC License +https://github.com/npm/node-semver -%% semver NOTICES AND INFORMATION BEGIN HERE -========================================= The ISC License Copyright (c) Isaac Z. Schlueter and Contributors @@ -2269,11 +2424,13 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -========================================= -END OF semver NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +seti-ui 0.1.0 +https://github.com/jesseweed/seti-ui -%% seti-ui NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) 2014 Jesse Weed Permission is hereby granted, free of charge, to any person obtaining @@ -2294,11 +2451,13 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF seti-ui NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +shaders-tmLanguage 0.1.0 - MIT +https://github.com/tgjones/shaders-tmLanguage -%% shaders-tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2017 Tim Jones @@ -2320,11 +2479,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF shaders-tmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +sumneko/lua.tmbundle 1.0.0 - TextMate Bundle License +https://github.com/sumneko/lua.tmbundle -%% sumneko/lua.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) sumneko-lua.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2338,11 +2499,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF sumneko/lua.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/asp.vb.net.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/asp.vb.net.tmbundle -%% textmate/asp.vb.net.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-asp.vb.net.tmbundle project authors If not otherwise specified (see below), files in this folder fall under the following license: @@ -2356,11 +2519,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/asp.vb.net.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/c.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/c.tmbundle -%% textmate/c.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-c.tmbundle authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2374,11 +2539,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/c.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/diff.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/diff.tmbundle -%% textmate/diff.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-diff.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2392,11 +2559,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/diff.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/git.tmbundle 0.0.0 - MIT +https://github.com/textmate/git.tmbundle -%% textmate/git.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2008 Tim Harper @@ -2419,11 +2588,13 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF textmate/git.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/groovy.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/groovy.tmbundle -%% textmate/groovy.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-groovy.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2437,11 +2608,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/groovy.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/html.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/html.tmbundle -%% textmate/html.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-html.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2455,11 +2628,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/html.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/ini.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/ini.tmbundle -%% textmate/ini.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-ini.tmbundle project authors If not otherwise specified (see below), files in this folder fall under the following license: @@ -2473,11 +2648,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/ini.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/javascript.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/javascript.tmbundle -%% textmate/javascript.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-javascript.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2491,11 +2668,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/javascript.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/markdown.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/markdown.tmbundle -%% textmate/markdown.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) markdown.tmbundle authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2509,11 +2688,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/markdown.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/perl.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/perl.tmbundle -%% textmate/perl.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-perl.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2527,11 +2708,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/perl.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/ruby.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/ruby.tmbundle -%% textmate/ruby.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-ruby.tmbundle project authors If not otherwise specified (see below), files in this folder fall under the following license: @@ -2545,11 +2728,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/ruby.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/yaml.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/yaml.tmbundle -%% textmate/yaml.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) 2015 FichteFoll Permission is hereby granted, free of charge, to any person obtaining a copy @@ -2568,11 +2753,13 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF textmate/yaml.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +trond-snekvik/vscode-rst 1.5.1 - MIT +https://github.com/trond-snekvik/vscode-rst -%% trond-snekvik/vscode-rst NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright 2021 Trond Snekvik @@ -2582,11 +2769,14 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF trond-snekvik/vscode-rst NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +TypeScript-TmLanguage 0.1.8 - MIT +TypeScript-TmLanguage 1.0.0 - MIT +https://github.com/microsoft/TypeScript-TmLanguage -%% TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) Microsoft Corporation All rights reserved. @@ -2609,11 +2799,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF TypeScript-TmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Unicode 12.0.0 - UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +https://home.unicode.org/ -%% Unicode NOTICES AND INFORMATION BEGIN HERE -========================================= Unicode Data Files include all data files under the directories https://www.unicode.org/Public/, https://www.unicode.org/reports/, https://cldr.unicode.org, https://github.com/unicode-org/icu, and @@ -2669,11 +2861,13 @@ Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. -========================================= -END OF Unicode NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +vscode-codicons 0.0.14 - MIT and Creative Commons Attribution 4.0 +https://github.com/microsoft/vscode-codicons -%% vscode-codicons NOTICES AND INFORMATION BEGIN HERE -========================================= Attribution 4.0 International ======================================================================= @@ -3069,11 +3263,13 @@ the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. -========================================= -END OF vscode-codicons NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +vscode-logfile-highlighter 2.15.0 - MIT +https://github.com/emilast/vscode-logfile-highlighter -%% vscode-logfile-highlighter NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2015 emilast @@ -3095,11 +3291,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF vscode-logfile-highlighter NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +vscode-swift 0.0.1 - MIT +https://github.com/owensd/vscode-swift -%% vscode-swift NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2015 David Owens II @@ -3120,11 +3318,41 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF vscode-swift NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +vscode-win32-app-container-tokens +https://github.com/microsoft/vscode-win32-app-container-tokens + +MIT License + +Copyright (c) Microsoft Corporation. + +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 +--------------------------------------------------------- + +--------------------------------------------------------- + +Web Background Synchronization - Apache2 +https://github.com/WICG/background-sync -%% Web Background Synchronization NOTICES AND INFORMATION BEGIN HERE -========================================= Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -3326,5 +3554,4 @@ Apache License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -========================================= -END OF Web Background Synchronization NOTICES AND INFORMATION \ No newline at end of file +--------------------------------------------------------- \ No newline at end of file diff --git a/build/.cachesalt b/build/.cachesalt index 30d07f23725..4f9c24c0470 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -2022-05-10T08:20:50.162Z +2022-08-01T11:24:47.411Z diff --git a/build/.moduleignore b/build/.moduleignore index a2e1b715e1b..1a1461b2330 100644 --- a/build/.moduleignore +++ b/build/.moduleignore @@ -48,6 +48,11 @@ native-watchdog/build/** native-watchdog/src/** !native-watchdog/build/Release/*.node +node-vsce-sign/** +!node-vsce-sign/src/main.js +!node-vsce-sign/package.json +!node-vsce-sign/bin/** + spdlog/binding.gyp spdlog/build/** spdlog/deps/** @@ -122,10 +127,6 @@ vscode-windows-ca-certs/**/* node-addon-api/**/* prebuild-install/**/* -@microsoft/applicationinsights*/** -@microsoft/dynamicproto-js/** -!@microsoft/applicationinsights-web/dist/applicationinsights-web.min.js - # other node modules **/docs/** diff --git a/build/.webignore b/build/.webignore index f55882ba9d4..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/** @@ -33,6 +36,3 @@ xterm-addon-webgl/out/** # This makes sure the model is included in the package !@vscode/vscode-languagedetection/model/** -@microsoft/applicationinsights*/** -@microsoft/dynamicproto-js/** -!@microsoft/applicationinsights-web/dist/applicationinsights-web.min.js \ No newline at end of file diff --git a/build/azure-pipelines/cli/cli-compile-and-publish.yml b/build/azure-pipelines/cli/cli-compile-and-publish.yml new file mode 100644 index 00000000000..4c152a2481b --- /dev/null +++ b/build/azure-pipelines/cli/cli-compile-and-publish.yml @@ -0,0 +1,45 @@ +parameters: + - name: VSCODE_CLI_TARGET + type: string + - name: VSCODE_CLI_ARTIFACT + type: string + - name: VSCODE_CLI_ENV + type: object + default: {} + +steps: + - script: cargo build --release --target ${{ parameters.VSCODE_CLI_TARGET }} --bin=code + displayName: Compile ${{ parameters.VSCODE_CLI_TARGET }} + workingDirectory: $(Build.SourcesDirectory)/cli + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + ${{ each pair in parameters.VSCODE_CLI_ENV }}: + ${{ pair.key }}: ${{ pair.value }} + + - ${{ if or(contains(parameters.VSCODE_CLI_TARGET, '-windows-'), contains(parameters.VSCODE_CLI_TARGET, '-darwin')) }}: + - task: ArchiveFiles@2 + inputs: + ${{ if contains(parameters.VSCODE_CLI_TARGET, '-windows-') }}: + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code.exe + ${{ if contains(parameters.VSCODE_CLI_TARGET, '-darwin') }}: + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip + + - publish: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip + artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + displayName: Publish ${{ parameters.VSCODE_CLI_ARTIFACT }} artifact + + - ${{ else }}: + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code + includeRootFolder: false + archiveType: tar + tarCompression: gz + archiveFile: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz + + - publish: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz + artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + displayName: Publish ${{ parameters.VSCODE_CLI_ARTIFACT }} artifact diff --git a/build/azure-pipelines/cli/cli-darwin-sign.yml b/build/azure-pipelines/cli/cli-darwin-sign.yml new file mode 100644 index 00000000000..b8f9e965133 --- /dev/null +++ b/build/azure-pipelines/cli/cli-darwin-sign.yml @@ -0,0 +1,40 @@ +parameters: + - name: VSCODE_CLI_ARTIFACTS + type: object + default: [] + +steps: + - task: UseDotNet@2 + inputs: + version: 2.x + + - task: EsrpClientTool@1 + displayName: Download ESRPClient + + - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - task: DownloadPipelineArtifact@2 + displayName: Download ${{ target }} + inputs: + artifact: ${{ target }} + path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} + + - script: | + set -e + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.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) $(Build.ArtifactStagingDirectory)/pkg "*.zip" + displayName: Notarize + + - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - script: | + set -e + ASSET_ID=$(echo "${{ target }}" | sed "s/unsigned_//") + mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$ASSET_ID.zip + echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" + displayName: Set asset id variable + + - publish: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$(ASSET_ID).zip + artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/cli/cli-win32-sign.yml b/build/azure-pipelines/cli/cli-win32-sign.yml new file mode 100644 index 00000000000..26e303c2842 --- /dev/null +++ b/build/azure-pipelines/cli/cli-win32-sign.yml @@ -0,0 +1,65 @@ +parameters: + - name: VSCODE_CLI_ARTIFACTS + type: object + default: [] + +steps: + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "ESRP-PKI,esrp-aad-username,esrp-aad-password" + + - task: UseDotNet@2 + displayName: "Use .NET" + inputs: + version: 3.x + + - task: EsrpClientTool@1 + displayName: "Use ESRP client" + + - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - task: DownloadPipelineArtifact@2 + displayName: Download artifacts + inputs: + artifact: ${{ target }} + path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} + + - task: ExtractFiles@1 + inputs: + archiveFilePatterns: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/*.zip + destinationFolder: $(Build.ArtifactStagingDirectory)/sign/${{ target }} + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $EsrpClientTool = (gci -directory -filter EsrpClientTool_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName + $EsrpCliZip = (gci -recurse -filter esrpcli.*.zip $EsrpClientTool | Select-Object -last 1).FullName + mkdir -p $(Agent.TempDirectory)\esrpcli + Expand-Archive -Path $EsrpCliZip -DestinationPath $(Agent.TempDirectory)\esrpcli + $EsrpCliDllPath = (gci -recurse -filter esrpcli.dll $(Agent.TempDirectory)\esrpcli | Select-Object -last 1).FullName + echo "##vso[task.setvariable variable=EsrpCliDllPath]$EsrpCliDllPath" + displayName: Find ESRP CLI + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/sign "*.exe" } + displayName: "Code sign" + + - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - powershell: | + $ASSET_ID = "${{ target }}".replace("unsigned_", ""); + echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" + displayName: Set asset id variable + + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/code.exe + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip + + - publish: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip + artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/cli/install-rust-posix.yml b/build/azure-pipelines/cli/install-rust-posix.yml new file mode 100644 index 00000000000..e32a8eedadf --- /dev/null +++ b/build/azure-pipelines/cli/install-rust-posix.yml @@ -0,0 +1,37 @@ +parameters: + - name: channel + type: string + default: stable + - name: targets + default: [] + type: object + +# Todo: use 1ES pipeline once extension is installed in ADO + +steps: + - script: | + set -e + curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + env: + RUSTUP_TOOLCHAIN: ${{ parameters.channel }} + displayName: "Install Rust" + + - script: | + set -e + rustup default $RUSTUP_TOOLCHAIN + rustup update $RUSTUP_TOOLCHAIN + env: + RUSTUP_TOOLCHAIN: ${{ parameters.channel }} + displayName: "Set Rust version" + + - ${{ each target in parameters.targets }}: + - script: rustup target add ${{ target }} + displayName: "Adding Rust target '${{ target }}'" + + - script: | + set -e + rustc --version + cargo --version + rustup --version + displayName: "Check Rust versions" diff --git a/build/azure-pipelines/cli/install-rust-win32.yml b/build/azure-pipelines/cli/install-rust-win32.yml new file mode 100644 index 00000000000..a1a250dcfbf --- /dev/null +++ b/build/azure-pipelines/cli/install-rust-win32.yml @@ -0,0 +1,38 @@ +parameters: + - name: channel + type: string + default: stable + - name: targets + default: [] + type: object + +# Todo: use 1ES pipeline once extension is installed in ADO + +steps: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + Invoke-WebRequest -Uri "https://win.rustup.rs" -Outfile $(Build.ArtifactStagingDirectory)/rustup-init.exe + exec { $(Build.ArtifactStagingDirectory)/rustup-init.exe -y --profile minimal --default-toolchain $env:RUSTUP_TOOLCHAIN --default-host x86_64-pc-windows-msvc } + echo "##vso[task.prependpath]$env:USERPROFILE\.cargo\bin" + env: + RUSTUP_TOOLCHAIN: ${{ parameters.channel }} + displayName: "Install Rust" + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + exec { rustup default $RUSTUP_TOOLCHAIN } + exec { rustup update $RUSTUP_TOOLCHAIN } + env: + RUSTUP_TOOLCHAIN: ${{ parameters.channel }} + displayName: "Set Rust version" + + - ${{ each target in parameters.targets }}: + - script: rustup target add ${{ target }} + displayName: "Adding Rust target '${{ target }}'" + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + exec { rustc --version } + exec { cargo --version } + exec { rustup --version } + displayName: "Check Rust versions" diff --git a/build/azure-pipelines/cli/prepare.js b/build/azure-pipelines/cli/prepare.js new file mode 100644 index 00000000000..b0cb2e6152a --- /dev/null +++ b/build/azure-pipelines/cli/prepare.js @@ -0,0 +1,66 @@ +"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 getVersion_1 = require("../../lib/getVersion"); +const fs = require("fs"); +const path = require("path"); +const packageJson = require("../../../package.json"); +const root = path.dirname(path.dirname(path.dirname(__dirname))); +const readJSON = (path) => JSON.parse(fs.readFileSync(path, 'utf8')); +let productJsonPath; +const isOSS = process.env.VSCODE_QUALITY === 'oss' || !process.env.VSCODE_QUALITY; +if (isOSS) { + productJsonPath = path.join(root, 'product.json'); +} +else { + productJsonPath = path.join(root, 'quality', process.env.VSCODE_QUALITY, 'product.json'); +} +console.log('Loading product.json from', productJsonPath); +const product = readJSON(productJsonPath); +const allProductsAndQualities = isOSS ? [product] : fs.readdirSync(path.join(root, 'quality')) + .map(quality => ({ quality, json: readJSON(path.join(root, 'quality', quality, 'product.json')) })); +const commit = (0, getVersion_1.getVersion)(root); +const makeQualityMap = (m) => { + const output = {}; + for (const { quality, json } of allProductsAndQualities) { + output[quality] = m(json, quality); + } + return output; +}; +/** + * Sets build environment variables for the CLI for current contextual info. + */ +const setLauncherEnvironmentVars = () => { + const vars = new Map([ + ['VSCODE_CLI_REMOTE_LICENSE_TEXT', product.serverLicense?.join('\\n')], + ['VSCODE_CLI_REMOTE_LICENSE_PROMPT', product.serverLicensePrompt], + ['VSCODE_CLI_AI_KEY', product.aiConfig?.cliKey], + ['VSCODE_CLI_AI_ENDPOINT', product.aiConfig?.cliEndpoint], + ['VSCODE_CLI_VERSION', packageJson.version], + ['VSCODE_CLI_UPDATE_ENDPOINT', product.updateUrl], + ['VSCODE_CLI_QUALITY', product.quality], + ['VSCODE_CLI_COMMIT', commit], + [ + 'VSCODE_CLI_WIN32_APP_IDS', + !isOSS && JSON.stringify(makeQualityMap(json => Object.entries(json) + .filter(([key]) => /^win32.*AppId$/.test(key)) + .map(([, value]) => String(value).replace(/[{}]/g, '')))), + ], + [ + 'VSCODE_CLI_QUALITY_DOWNLOAD_URIS', + !isOSS && JSON.stringify(makeQualityMap(json => json.downloadUrl)), + ], + ]); + console.log(JSON.stringify([...vars].reduce((obj, kv) => ({ ...obj, [kv[0]]: kv[1] }), {}))); + for (const [key, value] of vars) { + if (value) { + console.log(`##vso[task.setvariable variable=${key}]${value}`); + } + } +}; +if (require.main === module) { + setLauncherEnvironmentVars(); +} diff --git a/build/azure-pipelines/cli/prepare.ts b/build/azure-pipelines/cli/prepare.ts new file mode 100644 index 00000000000..53f33d08568 --- /dev/null +++ b/build/azure-pipelines/cli/prepare.ts @@ -0,0 +1,75 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { getVersion } from '../../lib/getVersion'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as packageJson from '../../../package.json'; + +const root = path.dirname(path.dirname(path.dirname(__dirname))); +const readJSON = (path: string) => JSON.parse(fs.readFileSync(path, 'utf8')); + +let productJsonPath: string; +const isOSS = process.env.VSCODE_QUALITY === 'oss' || !process.env.VSCODE_QUALITY; +if (isOSS) { + productJsonPath = path.join(root, 'product.json'); +} else { + productJsonPath = path.join(root, 'quality', process.env.VSCODE_QUALITY!, 'product.json'); +} + + +console.log('Loading product.json from', productJsonPath); +const product = readJSON(productJsonPath); +const allProductsAndQualities = isOSS ? [product] : fs.readdirSync(path.join(root, 'quality')) + .map(quality => ({ quality, json: readJSON(path.join(root, 'quality', quality, 'product.json')) })); +const commit = getVersion(root); + +const makeQualityMap = (m: (productJson: any, quality: string) => T): Record => { + const output: Record = {}; + for (const { quality, json } of allProductsAndQualities) { + output[quality] = m(json, quality); + } + return output; +}; + +/** + * Sets build environment variables for the CLI for current contextual info. + */ +const setLauncherEnvironmentVars = () => { + const vars = new Map([ + ['VSCODE_CLI_REMOTE_LICENSE_TEXT', product.serverLicense?.join('\\n')], + ['VSCODE_CLI_REMOTE_LICENSE_PROMPT', product.serverLicensePrompt], + ['VSCODE_CLI_AI_KEY', product.aiConfig?.cliKey], + ['VSCODE_CLI_AI_ENDPOINT', product.aiConfig?.cliEndpoint], + ['VSCODE_CLI_VERSION', packageJson.version], + ['VSCODE_CLI_UPDATE_ENDPOINT', product.updateUrl], + ['VSCODE_CLI_QUALITY', product.quality], + ['VSCODE_CLI_COMMIT', commit], + [ + 'VSCODE_CLI_WIN32_APP_IDS', + !isOSS && JSON.stringify( + makeQualityMap(json => Object.entries(json) + .filter(([key]) => /^win32.*AppId$/.test(key)) + .map(([, value]) => String(value).replace(/[{}]/g, ''))), + ), + ], + [ + 'VSCODE_CLI_QUALITY_DOWNLOAD_URIS', + !isOSS && JSON.stringify(makeQualityMap(json => json.downloadUrl)), + ], + ]); + + console.log(JSON.stringify([...vars].reduce((obj, kv) => ({...obj, [kv[0]]: kv[1]}), {}))); + + for (const [key, value] of vars) { + if (value) { + console.log(`##vso[task.setvariable variable=${key}]${value}`); + } + } +}; + +if (require.main === module) { + setLauncherEnvironmentVars(); +} diff --git a/build/azure-pipelines/cli/test.yml b/build/azure-pipelines/cli/test.yml new file mode 100644 index 00000000000..70eb714c1d9 --- /dev/null +++ b/build/azure-pipelines/cli/test.yml @@ -0,0 +1,21 @@ +parameters: + - name: VSCODE_CLI_TARGETS + default: [] + type: object + - name: VSCODE_CLI_RUST_CHANNEL + type: string + default: stable + +steps: + - template: ./install-rust-posix.yml + parameters: + targets: [] + channel: ${{ parameters.VSCODE_CLI_RUST_CHANNEL }} + + - script: rustup component add clippy && cargo clippy -- -D warnings + workingDirectory: cli + displayName: Clippy lint + + - script: cargo test + workingDirectory: cli + displayName: Run unit tests 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/common/computeNodeModulesCacheKey.js b/build/azure-pipelines/common/computeNodeModulesCacheKey.js index d15ceb6ef08..6cfa9323e71 100644 --- a/build/azure-pipelines/common/computeNodeModulesCacheKey.js +++ b/build/azure-pipelines/common/computeNodeModulesCacheKey.js @@ -1,8 +1,8 @@ +"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 }); const fs = require("fs"); const path = require("path"); @@ -14,7 +14,7 @@ shasum.update(fs.readFileSync(path.join(ROOT, 'build/.cachesalt'))); shasum.update(fs.readFileSync(path.join(ROOT, '.yarnrc'))); shasum.update(fs.readFileSync(path.join(ROOT, 'remote/.yarnrc'))); // Add `package.json` and `yarn.lock` files -for (let dir of dirs) { +for (const dir of dirs) { const packageJsonPath = path.join(ROOT, dir, 'package.json'); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString()); const relevantPackageJsonSections = { diff --git a/build/azure-pipelines/common/computeNodeModulesCacheKey.ts b/build/azure-pipelines/common/computeNodeModulesCacheKey.ts index 2eed5fe7adb..751f928da9f 100644 --- a/build/azure-pipelines/common/computeNodeModulesCacheKey.ts +++ b/build/azure-pipelines/common/computeNodeModulesCacheKey.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as fs from 'fs'; import * as path from 'path'; import * as crypto from 'crypto'; @@ -19,7 +17,7 @@ shasum.update(fs.readFileSync(path.join(ROOT, '.yarnrc'))); shasum.update(fs.readFileSync(path.join(ROOT, 'remote/.yarnrc'))); // Add `package.json` and `yarn.lock` files -for (let dir of dirs) { +for (const dir of dirs) { const packageJsonPath = path.join(ROOT, dir, 'package.json'); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString()); const relevantPackageJsonSections = { diff --git a/build/azure-pipelines/common/createAsset.js b/build/azure-pipelines/common/createAsset.js index 57207e25cfe..10f1503f666 100644 --- a/build/azure-pipelines/common/createAsset.js +++ b/build/azure-pipelines/common/createAsset.js @@ -1,8 +1,8 @@ +"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 }); const fs = require("fs"); const crypto = require("crypto"); @@ -43,6 +43,8 @@ function getPlatform(product, os, arch, type) { throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; + case 'cli': + return `cli-win32-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -52,6 +54,8 @@ function getPlatform(product, os, arch, type) { return `server-alpine-${arch}`; case 'web': return `server-alpine-${arch}-web`; + case 'cli': + return `cli-alpine-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -74,6 +78,8 @@ function getPlatform(product, os, arch, type) { return `linux-deb-${arch}`; case 'rpm-package': return `linux-rpm-${arch}`; + case 'cli': + return `cli-linux-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -94,6 +100,8 @@ function getPlatform(product, os, arch, type) { return 'server-darwin-web'; } return `server-darwin-${arch}-web`; + case 'cli': + return `cli-darwin-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -150,11 +158,6 @@ async function main() { const blobServiceClient = new storage_blob_1.BlobServiceClient(`https://vscode.blob.core.windows.net`, credential, storagePipelineOptions); const containerClient = blobServiceClient.getContainerClient(quality); const blobClient = containerClient.getBlockBlobClient(blobName); - const blobExists = await blobClient.exists(); - if (blobExists) { - console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`); - return; - } const blobOptions = { blobHTTPHeaders: { blobContentType: mime.lookup(filePath), @@ -162,29 +165,42 @@ async function main() { blobCacheControl: 'max-age=31536000, public' } }; - const uploadPromises = [ - (0, retry_1.retry)(async () => { + const uploadPromises = []; + if (await blobClient.exists()) { + console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`); + } + else { + uploadPromises.push((0, retry_1.retry)(async () => { await blobClient.uploadFile(filePath, blobOptions); console.log('Blob successfully uploaded to Azure storage.'); - }) - ]; + })); + } const shouldUploadToMooncake = /true/i.test(process.env['VSCODE_PUBLISH_TO_MOONCAKE'] ?? 'true'); if (shouldUploadToMooncake) { const mooncakeCredential = new identity_1.ClientSecretCredential(process.env['AZURE_MOONCAKE_TENANT_ID'], process.env['AZURE_MOONCAKE_CLIENT_ID'], process.env['AZURE_MOONCAKE_CLIENT_SECRET']); const mooncakeBlobServiceClient = new storage_blob_1.BlobServiceClient(`https://vscode.blob.core.chinacloudapi.cn`, mooncakeCredential, storagePipelineOptions); const mooncakeContainerClient = mooncakeBlobServiceClient.getContainerClient(quality); const mooncakeBlobClient = mooncakeContainerClient.getBlockBlobClient(blobName); - uploadPromises.push((0, retry_1.retry)(async () => { - await mooncakeBlobClient.uploadFile(filePath, blobOptions); - console.log('Blob successfully uploaded to Mooncake Azure storage.'); - })); - console.log('Uploading blobs to Azure storage and Mooncake Azure storage...'); + if (await mooncakeBlobClient.exists()) { + console.log(`Mooncake Blob ${quality}, ${blobName} already exists, not publishing again.`); + } + else { + uploadPromises.push((0, retry_1.retry)(async () => { + await mooncakeBlobClient.uploadFile(filePath, blobOptions); + console.log('Blob successfully uploaded to Mooncake Azure storage.'); + })); + } + if (uploadPromises.length) { + console.log('Uploading blobs to Azure storage and Mooncake Azure storage...'); + } } else { - console.log('Uploading blobs to Azure storage...'); + if (uploadPromises.length) { + console.log('Uploading blobs to Azure storage...'); + } } await Promise.all(uploadPromises); - console.log('All blobs successfully uploaded.'); + console.log(uploadPromises.length ? 'All blobs successfully uploaded.' : 'No blobs to upload.'); const assetUrl = `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`; const blobPath = new URL(assetUrl).pathname; const mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`; diff --git a/build/azure-pipelines/common/createAsset.ts b/build/azure-pipelines/common/createAsset.ts index 769b50e079d..139338dd24b 100644 --- a/build/azure-pipelines/common/createAsset.ts +++ b/build/azure-pipelines/common/createAsset.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as fs from 'fs'; import { Readable } from 'stream'; import * as crypto from 'crypto'; @@ -58,6 +56,8 @@ function getPlatform(product: string, os: string, arch: string, type: string): s throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; + case 'cli': + return `cli-win32-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -67,6 +67,8 @@ function getPlatform(product: string, os: string, arch: string, type: string): s return `server-alpine-${arch}`; case 'web': return `server-alpine-${arch}-web`; + case 'cli': + return `cli-alpine-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -89,6 +91,8 @@ function getPlatform(product: string, os: string, arch: string, type: string): s return `linux-deb-${arch}`; case 'rpm-package': return `linux-rpm-${arch}`; + case 'cli': + return `cli-linux-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -109,6 +113,8 @@ function getPlatform(product: string, os: string, arch: string, type: string): s return 'server-darwin-web'; } return `server-darwin-${arch}-web`; + case 'cli': + return `cli-darwin-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -180,12 +186,6 @@ async function main(): Promise { const blobServiceClient = new BlobServiceClient(`https://vscode.blob.core.windows.net`, credential, storagePipelineOptions); const containerClient = blobServiceClient.getContainerClient(quality); const blobClient = containerClient.getBlockBlobClient(blobName); - const blobExists = await blobClient.exists(); - - if (blobExists) { - console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`); - return; - } const blobOptions: BlockBlobParallelUploadOptions = { blobHTTPHeaders: { @@ -195,12 +195,15 @@ async function main(): Promise { } }; - const uploadPromises: Promise[] = [ - retry(async () => { + const uploadPromises: Promise[] = []; + if (await blobClient.exists()) { + console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`); + } else { + uploadPromises.push(retry(async () => { await blobClient.uploadFile(filePath, blobOptions); console.log('Blob successfully uploaded to Azure storage.'); - }) - ]; + })); + } const shouldUploadToMooncake = /true/i.test(process.env['VSCODE_PUBLISH_TO_MOONCAKE'] ?? 'true'); @@ -210,18 +213,27 @@ async function main(): Promise { const mooncakeContainerClient = mooncakeBlobServiceClient.getContainerClient(quality); const mooncakeBlobClient = mooncakeContainerClient.getBlockBlobClient(blobName); - uploadPromises.push(retry(async () => { - await mooncakeBlobClient.uploadFile(filePath, blobOptions); - console.log('Blob successfully uploaded to Mooncake Azure storage.'); - })); + if (await mooncakeBlobClient.exists()) { + console.log(`Mooncake Blob ${quality}, ${blobName} already exists, not publishing again.`); + } else { + uploadPromises.push(retry(async () => { + await mooncakeBlobClient.uploadFile(filePath, blobOptions); + console.log('Blob successfully uploaded to Mooncake Azure storage.'); + })); + } - console.log('Uploading blobs to Azure storage and Mooncake Azure storage...'); + if (uploadPromises.length) { + console.log('Uploading blobs to Azure storage and Mooncake Azure storage...'); + } } else { - console.log('Uploading blobs to Azure storage...'); + if (uploadPromises.length) { + console.log('Uploading blobs to Azure storage...'); + } } await Promise.all(uploadPromises); - console.log('All blobs successfully uploaded.'); + + console.log(uploadPromises.length ? 'All blobs successfully uploaded.' : 'No blobs to upload.'); const assetUrl = `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`; const blobPath = new URL(assetUrl).pathname; diff --git a/build/azure-pipelines/common/createBuild.js b/build/azure-pipelines/common/createBuild.js index 57bb87fedcf..afff1f111b3 100644 --- a/build/azure-pipelines/common/createBuild.js +++ b/build/azure-pipelines/common/createBuild.js @@ -1,8 +1,8 @@ +"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 }); const identity_1 = require("@azure/identity"); const cosmos_1 = require("@azure/cosmos"); diff --git a/build/azure-pipelines/common/createBuild.ts b/build/azure-pipelines/common/createBuild.ts index 8b1db94c412..512f3610116 100644 --- a/build/azure-pipelines/common/createBuild.ts +++ b/build/azure-pipelines/common/createBuild.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import { ClientSecretCredential } from '@azure/identity'; import { CosmosClient } from '@azure/cosmos'; import { retry } from './retry'; diff --git a/build/azure-pipelines/common/installPlaywright.js b/build/azure-pipelines/common/installPlaywright.js index af4bd5fb54c..dbc5835243f 100644 --- a/build/azure-pipelines/common/installPlaywright.js +++ b/build/azure-pipelines/common/installPlaywright.js @@ -3,10 +3,9 @@ * 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 retry_1 = require("./retry"); +process.env.DEBUG = 'pw:install'; // enable logging for this (https://github.com/microsoft/playwright/issues/17394) const { installDefaultBrowsersForNpmInstall } = require('playwright-core/lib/server'); async function install() { - await (0, retry_1.retry)(() => installDefaultBrowsersForNpmInstall()); + await installDefaultBrowsersForNpmInstall(); } install(); diff --git a/build/azure-pipelines/common/installPlaywright.ts b/build/azure-pipelines/common/installPlaywright.ts index 5d837a55413..742b6e0e399 100644 --- a/build/azure-pipelines/common/installPlaywright.ts +++ b/build/azure-pipelines/common/installPlaywright.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { retry } from './retry'; +process.env.DEBUG='pw:install'; // enable logging for this (https://github.com/microsoft/playwright/issues/17394) + const { installDefaultBrowsersForNpmInstall } = require('playwright-core/lib/server'); async function install() { - await retry(() => installDefaultBrowsersForNpmInstall()); + await installDefaultBrowsersForNpmInstall(); } install(); diff --git a/build/azure-pipelines/common/listNodeModules.js b/build/azure-pipelines/common/listNodeModules.js index 540569c79b5..644aa83d552 100644 --- a/build/azure-pipelines/common/listNodeModules.js +++ b/build/azure-pipelines/common/listNodeModules.js @@ -1,8 +1,8 @@ +"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 }); const fs = require("fs"); const path = require("path"); diff --git a/build/azure-pipelines/common/listNodeModules.ts b/build/azure-pipelines/common/listNodeModules.ts index 2ed6294477a..aca461f8b5f 100644 --- a/build/azure-pipelines/common/listNodeModules.ts +++ b/build/azure-pipelines/common/listNodeModules.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as fs from 'fs'; import * as path from 'path'; diff --git a/build/azure-pipelines/common/releaseBuild.js b/build/azure-pipelines/common/releaseBuild.js index 26dacf4d731..eba9b2dc8b7 100644 --- a/build/azure-pipelines/common/releaseBuild.js +++ b/build/azure-pipelines/common/releaseBuild.js @@ -1,8 +1,8 @@ +"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 }); const identity_1 = require("@azure/identity"); const cosmos_1 = require("@azure/cosmos"); @@ -28,22 +28,25 @@ async function getConfig(client, quality) { } return res.resources[0]; } -async function main() { +async function main(force) { const commit = process.env['VSCODE_DISTRO_COMMIT'] || getEnv('BUILD_SOURCEVERSION'); const quality = getEnv('VSCODE_QUALITY'); const aadCredentials = new identity_1.ClientSecretCredential(process.env['AZURE_TENANT_ID'], process.env['AZURE_CLIENT_ID'], process.env['AZURE_CLIENT_SECRET']); const client = new cosmos_1.CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT'], aadCredentials }); - const config = await getConfig(client, quality); - console.log('Quality config:', config); - if (config.frozen) { - console.log(`Skipping release because quality ${quality} is frozen.`); - return; + if (!force) { + const config = await getConfig(client, quality); + console.log('Quality config:', config); + if (config.frozen) { + console.log(`Skipping release because quality ${quality} is frozen.`); + return; + } } console.log(`Releasing build ${commit}...`); const scripts = client.database('builds').container(quality).scripts; await (0, retry_1.retry)(() => scripts.storedProcedure('releaseBuild').execute('', [commit])); } -main().then(() => { +const [, , force] = process.argv; +main(force === 'true').then(() => { console.log('Build successfully released'); process.exit(0); }, err => { diff --git a/build/azure-pipelines/common/releaseBuild.ts b/build/azure-pipelines/common/releaseBuild.ts index 064ac639e60..68476cc2952 100644 --- a/build/azure-pipelines/common/releaseBuild.ts +++ b/build/azure-pipelines/common/releaseBuild.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import { ClientSecretCredential } from '@azure/identity'; import { CosmosClient } from '@azure/cosmos'; import { retry } from './retry'; @@ -43,19 +41,22 @@ async function getConfig(client: CosmosClient, quality: string): Promise return res.resources[0] as Config; } -async function main(): Promise { +async function main(force: boolean): Promise { const commit = process.env['VSCODE_DISTRO_COMMIT'] || getEnv('BUILD_SOURCEVERSION'); const quality = getEnv('VSCODE_QUALITY'); const aadCredentials = new ClientSecretCredential(process.env['AZURE_TENANT_ID']!, process.env['AZURE_CLIENT_ID']!, process.env['AZURE_CLIENT_SECRET']!); const client = new CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT']!, aadCredentials }); - const config = await getConfig(client, quality); - console.log('Quality config:', config); + if (!force) { + const config = await getConfig(client, quality); - if (config.frozen) { - console.log(`Skipping release because quality ${quality} is frozen.`); - return; + console.log('Quality config:', config); + + if (config.frozen) { + console.log(`Skipping release because quality ${quality} is frozen.`); + return; + } } console.log(`Releasing build ${commit}...`); @@ -64,7 +65,9 @@ async function main(): Promise { await retry(() => scripts.storedProcedure('releaseBuild').execute('', [commit])); } -main().then(() => { +const [, , force] = process.argv; + +main(force === 'true').then(() => { console.log('Build successfully released'); process.exit(0); }, err => { diff --git a/build/azure-pipelines/common/retry.js b/build/azure-pipelines/common/retry.js index bd78d195abb..9c64a9b3226 100644 --- a/build/azure-pipelines/common/retry.js +++ b/build/azure-pipelines/common/retry.js @@ -1,8 +1,8 @@ +"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.retry = void 0; async function retry(fn) { diff --git a/build/azure-pipelines/common/retry.ts b/build/azure-pipelines/common/retry.ts index 0c766771da8..ed232245dec 100644 --- a/build/azure-pipelines/common/retry.ts +++ b/build/azure-pipelines/common/retry.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - export async function retry(fn: () => Promise): Promise { let lastError: Error | undefined; diff --git a/build/azure-pipelines/common/sign.js b/build/azure-pipelines/common/sign.js index 2c2168cacc3..a1ebcc90e40 100644 --- a/build/azure-pipelines/common/sign.js +++ b/build/azure-pipelines/common/sign.js @@ -13,6 +13,8 @@ function getParams(type) { switch (type) { case 'windows': return '[{"keyCode":"CP-230012","operationSetCode":"SigntoolSign","parameters":[{"parameterName":"OpusName","parameterValue":"VS Code"},{"parameterName":"OpusInfo","parameterValue":"https://code.visualstudio.com/"},{"parameterName":"Append","parameterValue":"/as"},{"parameterName":"FileDigest","parameterValue":"/fd \\"SHA256\\""},{"parameterName":"PageHash","parameterValue":"/NPH"},{"parameterName":"TimeStamp","parameterValue":"/tr \\"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\\" /td sha256"}],"toolName":"sign","toolVersion":"1.0"},{"keyCode":"CP-230012","operationSetCode":"SigntoolVerify","parameters":[{"parameterName":"VerifyAll","parameterValue":"/all"}],"toolName":"sign","toolVersion":"1.0"}]'; + case 'windows-appx': + return '[{"keyCode":"CP-229979","operationSetCode":"SigntoolSign","parameters":[{"parameterName":"OpusName","parameterValue":"VS Code"},{"parameterName":"OpusInfo","parameterValue":"https://code.visualstudio.com/"},{"parameterName":"FileDigest","parameterValue":"/fd \\"SHA256\\""},{"parameterName":"PageHash","parameterValue":"/NPH"},{"parameterName":"TimeStamp","parameterValue":"/tr \\"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\\" /td sha256"}],"toolName":"sign","toolVersion":"1.0"},{"keyCode":"CP-229979","operationSetCode":"SigntoolVerify","parameters":[],"toolName":"sign","toolVersion":"1.0"}]'; case 'rpm': return '[{ "keyCode": "CP-450779-Pgp", "operationSetCode": "LinuxSign", "parameters": [], "toolName": "sign", "toolVersion": "1.0" }]'; case 'darwin-sign': diff --git a/build/azure-pipelines/common/sign.ts b/build/azure-pipelines/common/sign.ts index a50ca698dfd..7f1916d26a2 100644 --- a/build/azure-pipelines/common/sign.ts +++ b/build/azure-pipelines/common/sign.ts @@ -12,6 +12,8 @@ function getParams(type: string): string { switch (type) { case 'windows': return '[{"keyCode":"CP-230012","operationSetCode":"SigntoolSign","parameters":[{"parameterName":"OpusName","parameterValue":"VS Code"},{"parameterName":"OpusInfo","parameterValue":"https://code.visualstudio.com/"},{"parameterName":"Append","parameterValue":"/as"},{"parameterName":"FileDigest","parameterValue":"/fd \\"SHA256\\""},{"parameterName":"PageHash","parameterValue":"/NPH"},{"parameterName":"TimeStamp","parameterValue":"/tr \\"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\\" /td sha256"}],"toolName":"sign","toolVersion":"1.0"},{"keyCode":"CP-230012","operationSetCode":"SigntoolVerify","parameters":[{"parameterName":"VerifyAll","parameterValue":"/all"}],"toolName":"sign","toolVersion":"1.0"}]'; + case 'windows-appx': + return '[{"keyCode":"CP-229979","operationSetCode":"SigntoolSign","parameters":[{"parameterName":"OpusName","parameterValue":"VS Code"},{"parameterName":"OpusInfo","parameterValue":"https://code.visualstudio.com/"},{"parameterName":"FileDigest","parameterValue":"/fd \\"SHA256\\""},{"parameterName":"PageHash","parameterValue":"/NPH"},{"parameterName":"TimeStamp","parameterValue":"/tr \\"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\\" /td sha256"}],"toolName":"sign","toolVersion":"1.0"},{"keyCode":"CP-229979","operationSetCode":"SigntoolVerify","parameters":[],"toolName":"sign","toolVersion":"1.0"}]'; case 'rpm': return '[{ "keyCode": "CP-450779-Pgp", "operationSetCode": "LinuxSign", "parameters": [], "toolName": "sign", "toolVersion": "1.0" }]'; case 'darwin-sign': diff --git a/build/azure-pipelines/darwin/cli-build-darwin.yml b/build/azure-pipelines/darwin/cli-build-darwin.yml new file mode 100644 index 00000000000..90e15d1c9e1 --- /dev/null +++ b/build/azure-pipelines/darwin/cli-build-darwin.yml @@ -0,0 +1,69 @@ +parameters: + - name: VSCODE_QUALITY + type: string + - name: VSCODE_BUILD_MACOS + type: boolean + default: false + - name: VSCODE_BUILD_MACOS_ARM64 + type: boolean + default: false + - name: channel + type: string + default: stable + +steps: + - task: Npm@1 + displayName: Download openssl prebuilt + inputs: + command: custom + customCommand: pack @vscode-internal/openssl-prebuilt@0.0.1 + customRegistry: useFeed + customFeed: 'Monaco/openssl-prebuilt' + workingDir: $(Build.ArtifactStagingDirectory) + + - script: | + set -e + mkdir $(Build.ArtifactStagingDirectory)/openssl + tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.1.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl + displayName: Extract openssl prebuilt + + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-posix.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - script: | + set -e + node build/azure-pipelines/cli/prepare.js + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-posix.yml + parameters: + targets: + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - x86_64-apple-darwin + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - aarch64-apple-darwin + + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: x86_64-apple-darwin + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_darwin_x64_cli + VSCODE_CLI_ENV: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-osx/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-osx/include + + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: aarch64-apple-darwin + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_darwin_arm64_cli + VSCODE_CLI_ENV: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-osx/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-osx/include diff --git a/build/azure-pipelines/darwin/helper-plugin-entitlements.plist b/build/azure-pipelines/darwin/helper-plugin-entitlements.plist new file mode 100644 index 00000000000..1cc1a152c74 --- /dev/null +++ b/build/azure-pipelines/darwin/helper-plugin-entitlements.plist @@ -0,0 +1,14 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.disable-library-validation + + + diff --git a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml new file mode 100644 index 00000000000..385697b412f --- /dev/null +++ b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml @@ -0,0 +1,55 @@ +parameters: + - name: VSCODE_BUILD_MACOS + type: boolean + - name: VSCODE_BUILD_MACOS_ARM64 + type: boolean + +steps: + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" + + - script: | + set -e + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication + + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry + + - script: | + set -e + for i in {1..3}; do # try 3 times + yarn --cwd build --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 + displayName: Install build dependencies + + - template: ../cli/cli-darwin-sign.yml + parameters: + VSCODE_CLI_ARTIFACTS: + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - unsigned_vscode_cli_darwin_x64_cli + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - unsigned_vscode_cli_darwin_arm64_cli diff --git a/build/azure-pipelines/darwin/product-build-darwin-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-sign.yml index f82e7a8b98d..79826b73541 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-sign.yml @@ -35,36 +35,95 @@ steps: git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") displayName: Merge distro + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry + - script: | - set -e - npx https://aka.ms/enablesecurefeed standAlone - timeoutInMinutes: 5 - retryCountOnTaskFailure: 3 - condition: and(succeeded(), eq(variables['ENABLE_TERRAPIN'], 'true')) - displayName: Switch to Terrapin packages + mkdir -p .build + node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash + displayName: Prepare yarn cache flags + + - 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: '"builtInDeps" | .build/builtindepshash' + path: .build/builtInExtensions + displayName: Restore built-in extensions - script: | set -e - for i in {1..3}; do # try 3 times, for Terrapin - yarn --cwd build --frozen-lockfile --check-files && break + tar -xzf .build/node_modules_cache/cache.tgz + displayName: Extract node_modules cache + condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true')) + + - 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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication + + - script: | + set -e + export npm_config_arch=$(VSCODE_ARCH) + export npm_config_node_gyp=$(which node-gyp) + + for i in {1..3}; do # try 3 times + 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 - displayName: Install build dependencies + 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 - download: current 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 @@ -74,20 +133,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: | @@ -100,9 +177,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 dd495426b6d..29c7bf90925 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-test.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-test.yml @@ -3,202 +3,62 @@ parameters: type: string - name: VSCODE_RUN_UNIT_TESTS type: boolean - default: true - name: VSCODE_RUN_INTEGRATION_TESTS type: boolean - default: true - name: VSCODE_RUN_SMOKE_TESTS type: boolean - default: true steps: - - task: NodeTool@0 - inputs: - versionSpec: "16.x" - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - 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 - - - script: | - set -e - tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz - displayName: Extract compilation output - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - # Set up the credentials to retrieve distro repo and setup git persona - # to create a merge commit for when we merge distro into oss - - script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF - - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF - echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - git checkout FETCH_HEAD - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") - displayName: Merge distro - - - script: | - mkdir -p .build - node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash - displayName: Prepare yarn cache flags - - - task: Cache@2 - inputs: - key: "nodeModules | $(Agent.OS) | .build/yarnlockhash" - path: .build/node_modules_cache - cacheHitVar: NODE_MODULES_RESTORED - displayName: Restore node_modules cache - - - 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 - 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 - export npm_config_arch=$(VSCODE_ARCH) - export npm_config_node_gyp=$(which node-gyp) - - 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/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 - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - # This script brings in the right resources (images, icons, etc) based on the quality (insiders, stable, exploration) - - script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality - - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-darwin-$(VSCODE_ARCH)-min-ci - displayName: Build client - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - 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 - - script: | set -e VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ yarn npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" displayName: Download Electron and Playwright - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - # Setting hardened entitlements is a requirement for: - # * Running tests on Big Sur (because Big Sur has additional security precautions) - - script: | - set -e - security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain - security default-keychain -s $(agent.tempdirectory)/buildagent.keychain - security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain - echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12 - security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain - VSCODE_ARCH=$(VSCODE_ARCH) DEBUG=electron-osx-sign* node build/darwin/sign.js - displayName: Set Hardened Entitlements - ${{ 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: | set -e yarn gulp \ + compile-extension:configuration-editing \ compile-extension:css-language-features-server \ compile-extension:emmet \ compile-extension:git \ @@ -206,50 +66,52 @@ 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 \ compile-extension:typescript-language-features \ compile-extension:vscode-api-tests \ compile-extension:vscode-colorize-tests \ - compile-extension:vscode-custom-editor-tests \ - compile-extension:vscode-notebook-tests \ compile-extension:vscode-test-resolver displayName: Build integration tests - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - ${{ 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: | @@ -259,35 +121,49 @@ 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 gulp compile-extension-media + displayName: Build extensions for smoke tests - - ${{ 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) + - script: | + set -e + yarn smoketest-no-compile --tracing + timeoutInMinutes: 20 + displayName: Run smoke tests (Electron) + + - ${{ 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 @@ -295,31 +171,47 @@ steps: continueOnError: true condition: succeededOrFailed() - - task: PublishPipelineArtifact@0 - inputs: - artifactName: crash-dump-macos-$(VSCODE_ARCH) - targetPath: .build/crashes - displayName: "Publish Crash Reports" - 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/crashes + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: crash-dump-macos-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: crash-dump-macos-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: crash-dump-macos-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Crash Reports" + continueOnError: true + condition: failed() - # In order to properly symbolify above crash reports - # (if any), we need the compiled native modules too - - task: PublishPipelineArtifact@0 - inputs: - artifactName: node-modules-macos-$(VSCODE_ARCH) - targetPath: node_modules - displayName: "Publish Node Modules" - continueOnError: true - condition: failed() + # In order to properly symbolify above crash reports + # (if any), we need the compiled native modules too + - task: PublishPipelineArtifact@0 + inputs: + targetPath: node_modules + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: node-modules-macos-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: node-modules-macos-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: node-modules-macos-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Node Modules" + continueOnError: true + condition: failed() - - task: PublishPipelineArtifact@0 - inputs: - artifactName: logs-macos-$(VSCODE_ARCH)-$(System.JobAttempt) - targetPath: .build/logs - displayName: "Publish Log Files" - continueOnError: true - condition: failed() + - task: PublishPipelineArtifact@0 + inputs: + targetPath: .build/logs + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: logs-macos-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: logs-macos-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: logs-macos-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Log Files" + continueOnError: true + condition: succeededOrFailed() - task: PublishTestResults@2 displayName: Publish Tests Results diff --git a/build/azure-pipelines/darwin/product-build-darwin-universal.yml b/build/azure-pipelines/darwin/product-build-darwin-universal.yml index 1b8cfef6737..5a3c3df5484 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-universal.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-universal.yml @@ -35,9 +35,14 @@ steps: git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") displayName: Merge distro + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry + - script: | mkdir -p .build - node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -47,10 +52,73 @@ 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 displayName: Extract node_modules cache + condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true')) + + - 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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication + + - script: | + set -e + export npm_config_arch=$(VSCODE_ARCH) + export npm_config_node_gyp=$(which node-gyp) + + for i in {1..3}; do # try 3 times + 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 - script: | set -e diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 5c524dd42fb..4962f8491ff 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -1,54 +1,84 @@ +parameters: + - name: VSCODE_PUBLISH + type: boolean + - name: VSCODE_QUALITY + type: string + - name: VSCODE_RUN_UNIT_TESTS + type: boolean + - name: VSCODE_RUN_INTEGRATION_TESTS + type: boolean + - name: VSCODE_RUN_SMOKE_TESTS + type: boolean + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean + steps: + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 + - task: NodeTool@0 inputs: versionSpec: "16.x" - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - KeyVaultName: vscode - SecretsFilter: "github-distro-mixin-password,macos-developer-certificate,macos-developer-certificate-key" + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + 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 - - script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling - - script: | - set -e - git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF - echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - git checkout FETCH_HEAD - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF + echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + git checkout FETCH_HEAD + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit - - script: | - set -e - git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") - displayName: Merge distro + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") + displayName: Merge distro + + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry - script: | mkdir -p .build - node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -58,6 +88,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 @@ -66,25 +102,24 @@ steps: - 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')) + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn - - 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 + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication - script: | set -e export npm_config_arch=$(VSCODE_ARCH) export npm_config_node_gyp=$(which node-gyp) - for i in {1..3}; do # try 3 times, for Terrapin + for i in {1..3}; do # try 3 times yarn --frozen-lockfile --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 @@ -99,6 +134,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 @@ -107,115 +149,175 @@ steps: condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) displayName: Create node_modules archive - # This script brings in the right resources (images, icons, etc) based on the quality (insiders, stable, exploration) - - script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + # This script brings in the right resources (images, icons, etc) based on the quality (insiders, stable, exploration) + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality + + - ${{ 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: | + set -e + node build/azure-pipelines/mixin --server + displayName: Mix in server quality + + - ${{ 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 - script: | set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-darwin-$(VSCODE_ARCH)-min-ci - displayName: Build client + APP_ROOT="$(Agent.BuildDirectory)/VSCode-darwin-$(VSCODE_ARCH)" + APP_NAME="`ls $APP_ROOT | head -n 1`" + echo "##vso[task.setvariable variable=APP_PATH]$APP_ROOT/$APP_NAME" + displayName: Find application path - - script: | - set -e - node build/azure-pipelines/mixin --server - displayName: Mix in server quality + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_darwin_arm64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - - 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 + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_darwin_x64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - # Setting hardened entitlements is a requirement for: - # * Apple notarization - # * Running tests on Big Sur (because Big Sur has additional security precautions) - - script: | - set -e - security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain - security default-keychain -s $(agent.tempdirectory)/buildagent.keychain - security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain - echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12 - security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain - VSCODE_ARCH=$(VSCODE_ARCH) DEBUG=electron-osx-sign* node build/darwin/sign.js - displayName: Set Hardened Entitlements + - script: | + set -e + ARCHIVE_NAME=$(ls "$(Build.ArtifactStagingDirectory)/cli" | head -n 1) + unzip "$(Build.ArtifactStagingDirectory)/cli/$ARCHIVE_NAME" -d "$(Build.ArtifactStagingDirectory)/cli" + CLI_APP_NAME=$(node -p "require(\"$(APP_PATH)/Contents/Resources/app/product.json\").tunnelApplicationName") + mv "$(Build.ArtifactStagingDirectory)/cli/code" "$(APP_PATH)/Contents/Resources/app/bin/$CLI_APP_NAME" + chmod +x "$(APP_PATH)/Contents/Resources/app/bin/$CLI_APP_NAME" + displayName: Make CLI executable - - script: | - set -e - pushd $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) && zip -r -X -y $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip * && popd - displayName: Archive build + - ${{ 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 }} - - script: | - set -e + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + # Setting hardened entitlements is a requirement for: + # * Apple notarization + # * Running tests on Big Sur (because Big Sur has additional security precautions) + - script: | + set -e + security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain + security default-keychain -s $(agent.tempdirectory)/buildagent.keychain + security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain + echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12 + security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain + VSCODE_ARCH=$(VSCODE_ARCH) DEBUG=electron-osx-sign* node build/darwin/sign.js + displayName: Set Hardened Entitlements - # package Remote Extension Host - pushd .. && mv vscode-reh-darwin-$(VSCODE_ARCH) vscode-server-darwin-$(VSCODE_ARCH) && zip -Xry vscode-server-darwin-$(VSCODE_ARCH).zip vscode-server-darwin-$(VSCODE_ARCH) && popd + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - script: | + set -e + pushd $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) && zip -r -X -y $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip * && popd + displayName: Archive build - # package Remote Extension Host (Web) - pushd .. && mv vscode-reh-web-darwin-$(VSCODE_ARCH) vscode-server-darwin-$(VSCODE_ARCH)-web && zip -Xry vscode-server-darwin-$(VSCODE_ARCH)-web.zip vscode-server-darwin-$(VSCODE_ARCH)-web && popd - displayName: Prepare to publish servers + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - script: | + set -e - - publish: $(Agent.BuildDirectory)/VSCode-darwin-$(VSCODE_ARCH).zip - artifact: unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive - displayName: Publish client archive + # package Remote Extension Host + pushd .. && mv vscode-reh-darwin-$(VSCODE_ARCH) vscode-server-darwin-$(VSCODE_ARCH) && zip -Xry vscode-server-darwin-$(VSCODE_ARCH).zip vscode-server-darwin-$(VSCODE_ARCH) && popd - - publish: $(Agent.BuildDirectory)/vscode-server-darwin-$(VSCODE_ARCH).zip - artifact: vscode_server_darwin_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish server archive + # package Remote Extension Host (Web) + pushd .. && mv vscode-reh-web-darwin-$(VSCODE_ARCH) vscode-server-darwin-$(VSCODE_ARCH)-web && zip -Xry vscode-server-darwin-$(VSCODE_ARCH)-web.zip vscode-server-darwin-$(VSCODE_ARCH)-web && popd + displayName: Prepare to publish servers - - publish: $(Agent.BuildDirectory)/vscode-server-darwin-$(VSCODE_ARCH)-web.zip - artifact: vscode_web_darwin_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish web server archive + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (client) + inputs: + BuildDropPath: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + PackageName: Visual Studio Code - - task: AzureCLI@2 - inputs: - azureSubscription: "vscode-builds-subscription" - scriptType: pscore - scriptLocation: inlineScript - addSpnToEnvironment: true - inlineScript: | - Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId" - Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId" - Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - publish: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (client) + artifact: vscode_client_darwin_$(VSCODE_ARCH)_sbom - - script: | - set -e - AZURE_STORAGE_ACCOUNT="ticino" \ - AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ - AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ - AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ - VSCODE_ARCH="$(VSCODE_ARCH)" \ - node build/azure-pipelines/upload-configuration - displayName: Upload configuration (for Bing settings search) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), ne(variables['VSCODE_PUBLISH'], 'false')) - continueOnError: true + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (server) + inputs: + BuildDropPath: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) + PackageName: Visual Studio Code Server - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (client) - inputs: - BuildDropPath: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) - PackageName: Visual Studio Code - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - publish: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (server) + artifact: vscode_server_darwin_$(VSCODE_ARCH)_sbom - - publish: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (client) - artifact: vscode_client_darwin_$(VSCODE_ARCH)_sbom - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - publish: $(Agent.BuildDirectory)/VSCode-darwin-$(VSCODE_ARCH).zip + artifact: unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive + displayName: Publish client archive - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (server) - inputs: - BuildDropPath: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) - PackageName: Visual Studio Code Server - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - publish: $(Agent.BuildDirectory)/vscode-server-darwin-$(VSCODE_ARCH).zip + artifact: vscode_server_darwin_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish server archive - - publish: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (server) - artifact: vscode_server_darwin_$(VSCODE_ARCH)_sbom - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - publish: $(Agent.BuildDirectory)/vscode-server-darwin-$(VSCODE_ARCH)-web.zip + artifact: vscode_web_darwin_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish web server archive + + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - task: AzureCLI@2 + inputs: + azureSubscription: "vscode-builds-subscription" + scriptType: pscore + scriptLocation: inlineScript + addSpnToEnvironment: true + inlineScript: | + Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId" + Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId" + Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" + + - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + - script: | + set -e + AZURE_STORAGE_ACCOUNT="ticino" \ + AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ + AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ + AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ + VSCODE_ARCH="$(VSCODE_ARCH)" \ + node build/azure-pipelines/upload-configuration + displayName: Upload configuration (for Bing settings search) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + continueOnError: true diff --git a/build/azure-pipelines/linux/cli-build-linux.yml b/build/azure-pipelines/linux/cli-build-linux.yml new file mode 100644 index 00000000000..b7b10504b4d --- /dev/null +++ b/build/azure-pipelines/linux/cli-build-linux.yml @@ -0,0 +1,138 @@ +parameters: + - name: VSCODE_BUILD_LINUX_ALPINE + type: boolean + default: false + - name: VSCODE_BUILD_LINUX + type: boolean + default: false + - name: VSCODE_BUILD_LINUX_ALPINE_ARM64 + type: boolean + default: false + - name: VSCODE_BUILD_LINUX_ARM64 + type: boolean + default: false + - name: VSCODE_BUILD_LINUX_ARMHF + type: boolean + default: false + - name: VSCODE_QUALITY + type: string + - name: channel + type: string + default: stable + +steps: + - task: Npm@1 + displayName: Download openssl prebuilt + inputs: + command: custom + customCommand: pack @vscode-internal/openssl-prebuilt@0.0.1 + customRegistry: useFeed + customFeed: 'Monaco/openssl-prebuilt' + workingDir: $(Build.ArtifactStagingDirectory) + + - script: | + set -e + mkdir $(Build.ArtifactStagingDirectory)/openssl + tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.1.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl + displayName: Extract openssl prebuilt + + # inspired by: https://github.com/emk/rust-musl-builder/blob/main/Dockerfile + - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }}: + - bash: | + set -e + sudo apt-get update + sudo apt-get install -yq build-essential musl-dev musl-tools linux-libc-dev pkgconf xutils-dev + sudo ln -s "/usr/bin/g++" "/usr/bin/musl-g++" || echo "link exists" + displayName: Install musl build dependencies + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true) }}: + - bash: | + set -e + sudo apt-get install -yq gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf + displayName: Install arm32 toolchains + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: + - bash: | + set -e + sudo apt-get install -yq gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu + displayName: Install arm64 toolchains + + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-posix.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - script: | + set -e + node build/azure-pipelines/cli/prepare.js + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-posix.yml + parameters: + targets: + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: + - aarch64-unknown-linux-musl + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: + - x86_64-unknown-linux-musl + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: + - aarch64-unknown-linux-gnu + - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: + - x86_64-unknown-linux-gnu + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true) }}: + - armv7-unknown-linux-gnueabihf + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: aarch64-unknown-linux-musl + VSCODE_CLI_ARTIFACT: vscode_cli_alpine_arm64_cli + VSCODE_CLI_ENV: + CXX_aarch64-unknown-linux-musl: musl-g++ + CC_aarch64-unknown-linux-musl: musl-gcc + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-linux/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-linux/include + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: x86_64-unknown-linux-musl + VSCODE_CLI_ARTIFACT: vscode_cli_alpine_x64_cli + VSCODE_CLI_ENV: + CXX_aarch64-unknown-linux-musl: musl-g++ + CC_aarch64-unknown-linux-musl: musl-gcc + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-linux/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-linux/include + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: aarch64-unknown-linux-gnu + VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli + VSCODE_CLI_ENV: + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-linux/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-linux/include + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: x86_64-unknown-linux-gnu + VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli + VSCODE_CLI_ENV: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-linux/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-linux/include + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: armv7-unknown-linux-gnueabihf + VSCODE_CLI_ARTIFACT: vscode_cli_linux_armhf_cli + VSCODE_CLI_ENV: + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm-linux/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm-linux/include diff --git a/build/azure-pipelines/linux/product-build-alpine.yml b/build/azure-pipelines/linux/product-build-alpine.yml index 3aef7279243..2175c76556e 100644 --- a/build/azure-pipelines/linux/product-build-alpine.yml +++ b/build/azure-pipelines/linux/product-build-alpine.yml @@ -55,9 +55,14 @@ steps: git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") displayName: Merge distro + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry + - script: | mkdir -p .build - node build/azure-pipelines/common/computeNodeModulesCacheKey.js "alpine" $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeNodeModulesCacheKey.js "alpine" > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -67,6 +72,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 @@ -75,15 +86,21 @@ steps: - 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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication - script: | set -e - for i in {1..3}; do # try 3 times, for Terrapin + for i in {1..3}; do # try 3 times yarn --frozen-lockfile --check-files --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 @@ -98,6 +115,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 new file mode 100644 index 00000000000..36495873d96 --- /dev/null +++ b/build/azure-pipelines/linux/product-build-linux-client-test.yml @@ -0,0 +1,278 @@ +parameters: + - name: VSCODE_QUALITY + type: string + - name: VSCODE_RUN_UNIT_TESTS + type: boolean + - name: VSCODE_RUN_INTEGRATION_TESTS + type: boolean + - name: VSCODE_RUN_SMOKE_TESTS + type: boolean + +steps: + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" + displayName: Download Electron and Playwright + + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + 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 ne(parameters.VSCODE_QUALITY, 'oss') }}: + - 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 + 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: | + set -e + yarn gulp \ + compile-extension:configuration-editing \ + compile-extension:css-language-features-server \ + compile-extension:emmet \ + compile-extension:git \ + compile-extension:github-authentication \ + 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 \ + compile-extension:typescript-language-features \ + compile-extension:vscode-api-tests \ + compile-extension:vscode-colorize-tests \ + compile-extension:vscode-test-resolver + displayName: Build integration tests + + - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: + - ${{ 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 + + - script: | + set -e + ./scripts/test-web-integration.sh --browser chromium + displayName: Run integration tests (Browser, Chromium) + 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: | + set -e + ps -ef + cat /proc/sys/fs/inotify/max_user_watches + lsof | wc -l + displayName: Diagnostics before smoke test run (processes, max_user_watches, number of opened file handles) + continueOnError: true + condition: succeededOrFailed() + + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + yarn --cwd test/smoke compile + displayName: Compile smoke tests + + - script: | + set -e + yarn gulp \ + compile-extension:markdown-language-features \ + compile-extension-media + displayName: Build extensions for smoke tests + + - script: | + set -e + yarn smoketest-no-compile --tracing + timeoutInMinutes: 20 + displayName: Run smoke tests (Electron) + + - 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) + + - script: | + set -e + ps -ef + cat /proc/sys/fs/inotify/max_user_watches + lsof | wc -l + displayName: Diagnostics after smoke test run (processes, max_user_watches, number of opened file handles) + continueOnError: true + condition: succeededOrFailed() + + - ${{ if or(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + - task: PublishPipelineArtifact@0 + inputs: + targetPath: .build/crashes + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: crash-dump-linux-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: crash-dump-linux-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: crash-dump-linux-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Crash Reports" + continueOnError: true + condition: failed() + + # In order to properly symbolify above crash reports + # (if any), we need the compiled native modules too + - task: PublishPipelineArtifact@0 + inputs: + targetPath: node_modules + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: node-modules-linux-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: node-modules-linux-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: node-modules-linux-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Node Modules" + continueOnError: true + condition: failed() + + - task: PublishPipelineArtifact@0 + inputs: + targetPath: .build/logs + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: logs-linux-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: logs-linux-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: logs-linux-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Log Files" + continueOnError: true + condition: succeededOrFailed() + + - task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: "*-results.xml" + searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" + condition: succeededOrFailed() diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 8f3b4aad146..099b2eae733 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -1,96 +1,126 @@ parameters: + - name: VSCODE_PUBLISH + type: boolean - name: VSCODE_QUALITY type: string - name: VSCODE_RUN_UNIT_TESTS type: boolean - default: true - name: VSCODE_RUN_INTEGRATION_TESTS type: boolean - default: true - name: VSCODE_RUN_SMOKE_TESTS type: boolean - default: true + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean steps: + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 + - task: NodeTool@0 inputs: versionSpec: "16.x" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - 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 - - - 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')) - - - script: | - set -e - tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz - displayName: Extract compilation output + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF - - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + - task: DownloadPipelineArtifact@2 + inputs: + artifact: Compilation + path: $(Build.ArtifactStagingDirectory) + displayName: Download compilation output - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF - echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - git checkout FETCH_HEAD - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit + - 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') }}: - - script: | - set -e - git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") - displayName: Merge distro + - 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 + tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz + displayName: Extract compilation output + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF + + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF + echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + git checkout FETCH_HEAD + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") + displayName: Merge distro + + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry - script: | mkdir -p .build - node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH > .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 @@ -100,16 +130,22 @@ steps: - 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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication - script: | set -e node build/npm/setupBuildYarnrc - for i in {1..3}; do # try 3 times, for Terrapin + for i in {1..3}; do # try 3 times yarn --cwd build --frozen-lockfile --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 @@ -155,7 +191,7 @@ steps: export VSCODE_REMOTE_CXX=$(which g++) fi - for i in {1..3}; do # try 3 times, for Terrapin + for i in {1..3}; do # try 3 times yarn --frozen-lockfile --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 @@ -172,10 +208,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 @@ -186,319 +230,167 @@ steps: displayName: Create node_modules archive - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality - - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-linux-$(VSCODE_ARCH)-min-ci - displayName: Build + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - 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 - - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - 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) }}: - - script: | - set -e - ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - - script: | - set -e - yarn test-node --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - script: | - set -e - yarn gulp \ - compile-extension:css-language-features-server \ - compile-extension:emmet \ - compile-extension:git \ - compile-extension:github-authentication \ - compile-extension:html-language-features-server \ - compile-extension:ipynb \ - compile-extension:json-language-features-server \ - compile-extension:markdown-language-features \ - compile-extension-media \ - compile-extension:microsoft-authentication \ - compile-extension:typescript-language-features \ - compile-extension:vscode-api-tests \ - compile-extension:vscode-colorize-tests \ - compile-extension:vscode-custom-editor-tests \ - compile-extension:vscode-notebook-tests \ - compile-extension:vscode-test-resolver - displayName: Build integration tests - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - script: | - set -e - ps -ef - cat /proc/sys/fs/inotify/max_user_watches - lsof | wc -l - displayName: Diagnostics before smoke test run (processes, max_user_watches, number of opened file handles) - continueOnError: true - condition: and(succeededOrFailed(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ 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) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ 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) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ 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) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - script: | - set -e - ps -ef - cat /proc/sys/fs/inotify/max_user_watches - lsof | wc -l - displayName: Diagnostics after smoke test run (processes, max_user_watches, number of opened file handles) - continueOnError: true - condition: and(succeededOrFailed(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - task: PublishPipelineArtifact@0 - inputs: - artifactName: crash-dump-linux-$(VSCODE_ARCH) - targetPath: .build/crashes - displayName: "Publish Crash Reports" - continueOnError: true - condition: failed() - - # In order to properly symbolify above crash reports - # (if any), we need the compiled native modules too - - task: PublishPipelineArtifact@0 - inputs: - artifactName: node-modules-linux-$(VSCODE_ARCH) - targetPath: node_modules - displayName: "Publish Node Modules" - continueOnError: true - condition: failed() - - - task: PublishPipelineArtifact@0 - inputs: - artifactName: logs-linux-$(VSCODE_ARCH)-$(System.JobAttempt) - targetPath: .build/logs - displayName: "Publish Log Files" - continueOnError: true - condition: and(failed(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - task: PublishTestResults@2 - displayName: Publish Tests Results - inputs: - testResultsFiles: "*-results.xml" - searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" - condition: and(succeededOrFailed(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - 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 - yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-deb" - yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-rpm" - displayName: Build deb, rpm packages - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - script: | + set -e + node build/azure-pipelines/mixin --server + displayName: Mix in server quality - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-snap" - displayName: Prepare snap package - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - 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') }}: - - task: UseDotNet@2 - inputs: - version: 2.x - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ 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 ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: EsrpClientTool@1 - displayName: Download ESRPClient - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: vscode_cli_linux_arm64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" rpm $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) .build/linux/rpm '*.rpm' - displayName: Codesign rpm - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - task: DownloadPipelineArtifact@2 + inputs: + artifact: vscode_cli_linux_x64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_ARCH="$(VSCODE_ARCH)" \ - ./build/azure-pipelines/linux/prepare-publish.sh - displayName: Prepare for Publish - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - task: DownloadPipelineArtifact@2 + inputs: + artifact: vscode_cli_linux_armhf_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'armhf')) - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(DEB_PATH) - artifact: vscode_client_linux_$(VSCODE_ARCH)_deb-package - displayName: Publish deb package - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - script: | + set -e + tar -xzvf $(Build.ArtifactStagingDirectory)/cli/*.tar.gz -C $(Build.ArtifactStagingDirectory)/cli + CLI_APP_NAME=$(node -p "require(\"$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/resources/app/product.json\").tunnelApplicationName") + mv $(Build.ArtifactStagingDirectory)/cli/code $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$CLI_APP_NAME + displayName: Make CLI executable - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(RPM_PATH) - artifact: vscode_client_linux_$(VSCODE_ARCH)_rpm-package - displayName: Publish rpm package - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ 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 }} - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(TARBALL_PATH) - artifact: vscode_client_linux_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish client archive - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - script: | + set -e + yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-deb" + yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-rpm" + displayName: Build deb, rpm packages - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH).tar.gz - artifact: vscode_server_linux_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish server archive - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - script: | + set -e + yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-snap" + displayName: Prepare snap package - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH)-web.tar.gz - artifact: vscode_web_linux_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish web server archive - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: UseDotNet@2 + inputs: + version: 2.x - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: PublishPipelineArtifact@0 - displayName: "Publish Pipeline Artifact" - inputs: - artifactName: "snap-$(VSCODE_ARCH)" - targetPath: .build/linux/snap-tarball - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: EsrpClientTool@1 + displayName: Download ESRPClient - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (client) - inputs: - BuildDropPath: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - PackageName: Visual Studio Code - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - script: | + set -e + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" rpm $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) .build/linux/rpm '*.rpm' + displayName: Codesign rpm - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (client) - artifact: vscode_client_linux_$(VSCODE_ARCH)_sbom - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - script: | + set -e + VSCODE_ARCH="$(VSCODE_ARCH)" \ + ./build/azure-pipelines/linux/prepare-publish.sh + displayName: Prepare for Publish - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (server) - inputs: - BuildDropPath: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) - PackageName: Visual Studio Code Server - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (client) + inputs: + BuildDropPath: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + PackageName: Visual Studio Code - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (server) - artifact: vscode_server_linux_$(VSCODE_ARCH)_sbom - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (client) + artifact: vscode_client_linux_$(VSCODE_ARCH)_sbom + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (server) + inputs: + BuildDropPath: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) + PackageName: Visual Studio Code Server + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (server) + artifact: vscode_server_linux_$(VSCODE_ARCH)_sbom + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(DEB_PATH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_deb-package + displayName: Publish deb package + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(RPM_PATH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_rpm-package + displayName: Publish rpm package + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(TARBALL_PATH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish client archive + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH).tar.gz + artifact: vscode_server_linux_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish server archive + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH)-web.tar.gz + artifact: vscode_web_linux_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish web server archive + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: PublishPipelineArtifact@0 + displayName: "Publish Pipeline Artifact" + inputs: + artifactName: "snap-$(VSCODE_ARCH)" + targetPath: .build/linux/snap-tarball diff --git a/build/azure-pipelines/linux/product-build-linux-server.yml b/build/azure-pipelines/linux/product-build-linux-server.yml index 8ab58da435c..ecc193d3fed 100644 --- a/build/azure-pipelines/linux/product-build-linux-server.yml +++ b/build/azure-pipelines/linux/product-build-linux-server.yml @@ -8,59 +8,69 @@ steps: versionSpec: "16.x" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - KeyVaultName: vscode - SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: Docker@1 - displayName: "Pull Docker image" - inputs: - azureSubscriptionEndpoint: "vscode-builds-subscription" - azureContainerRegistry: vscodehub.azurecr.io - command: "Run an image" - imageName: "vscode-linux-build-agent:centos7-devtoolset8-arm64" - containerCommand: uname - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + - task: Docker@1 + displayName: "Pull Docker image" + inputs: + azureSubscriptionEndpoint: "vscode-builds-subscription" + azureContainerRegistry: vscodehub.azurecr.io + command: "Run an image" + imageName: "vscode-linux-build-agent:centos7-devtoolset8-arm64" + containerCommand: uname + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF - echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - git checkout FETCH_HEAD - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit + - script: | + set -e + git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF + echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + git checkout FETCH_HEAD + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") - displayName: Merge distro + - script: | + set -e + git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") + displayName: Merge distro - 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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication + + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry - script: | set -e @@ -71,18 +81,18 @@ steps: condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - displayName: Register Docker QEMU - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + - script: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + displayName: Register Docker QEMU + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - docker run -e VSCODE_QUALITY -e GITHUB_TOKEN -v $(pwd):/root/vscode -v ~/.netrc:/root/.netrc vscodehub.azurecr.io/vscode-linux-build-agent:centos7-devtoolset8-arm64 /root/vscode/build/azure-pipelines/linux/scripts/install-remote-dependencies.sh - displayName: Install dependencies via qemu - env: - GITHUB_TOKEN: "$(github-distro-mixin-password)" - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + - script: | + set -e + docker run -e VSCODE_QUALITY -e GITHUB_TOKEN -v $(pwd):/root/vscode -v ~/.netrc:/root/.netrc vscodehub.azurecr.io/vscode-linux-build-agent:centos7-devtoolset8-arm64 /root/vscode/build/azure-pipelines/linux/scripts/install-remote-dependencies.sh + displayName: Install dependencies via qemu + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - script: | set -e diff --git a/build/azure-pipelines/linux/scripts/install-remote-dependencies.sh b/build/azure-pipelines/linux/scripts/install-remote-dependencies.sh index d2f62087661..c6b4e3115f1 100755 --- a/build/azure-pipelines/linux/scripts/install-remote-dependencies.sh +++ b/build/azure-pipelines/linux/scripts/install-remote-dependencies.sh @@ -4,7 +4,7 @@ set -e echo "Installing remote dependencies" (cd remote && rm -rf node_modules) -for i in {1..3}; do # try 3 times, for Terrapin +for i in {1..3}; do # try 3 times yarn --cwd remote --frozen-lockfile --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 diff --git a/build/azure-pipelines/mixin-distro-posix.yml b/build/azure-pipelines/mixin-distro-posix.yml new file mode 100644 index 00000000000..5340bda32d0 --- /dev/null +++ b/build/azure-pipelines/mixin-distro-posix.yml @@ -0,0 +1,40 @@ +parameters: + - name: VSCODE_QUALITY + type: string + +steps: + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password" + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF + + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF + echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + git checkout FETCH_HEAD + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") + displayName: Merge distro diff --git a/build/azure-pipelines/mixin-distro-win32.yml b/build/azure-pipelines/mixin-distro-win32.yml new file mode 100644 index 00000000000..5ff4eacf41c --- /dev/null +++ b/build/azure-pipelines/mixin-distro-win32.yml @@ -0,0 +1,40 @@ +parameters: + - name: VSCODE_QUALITY + type: string + +steps: + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password" + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII + + exec { git config user.email "vscode@microsoft.com" } + exec { git config user.name "VSCode" } + displayName: Prepare tooling + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + + exec { git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $(VSCODE_DISTRO_REF) } + Write-Host "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + exec { git checkout FETCH_HEAD } + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") } + displayName: Merge distro diff --git a/build/azure-pipelines/mixin.js b/build/azure-pipelines/mixin.js index 769ac72a9ee..273aeda9fc2 100644 --- a/build/azure-pipelines/mixin.js +++ b/build/azure-pipelines/mixin.js @@ -1,8 +1,8 @@ +"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 }); const json = require("gulp-json-editor"); const buffer = require('gulp-buffer'); diff --git a/build/azure-pipelines/mixin.ts b/build/azure-pipelines/mixin.ts index ccd98d6e773..aec694a61df 100644 --- a/build/azure-pipelines/mixin.ts +++ b/build/azure-pipelines/mixin.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as json from 'gulp-json-editor'; const buffer = require('gulp-buffer'); import * as filter from 'gulp-filter'; 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..73f17eea5ac --- /dev/null +++ b/build/azure-pipelines/product-build-pr-cache.yml @@ -0,0 +1,83 @@ +steps: + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 + + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry + + - script: | + mkdir -p .build + node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH > .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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication + + - script: | + set -e + for i in {1..3}; do # try 3 times + 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 3c45858413e..2ef55d4d05f 100644 --- a/build/azure-pipelines/product-build-pr.yml +++ b/build/azure-pipelines/product-build-pr.yml @@ -6,22 +6,15 @@ 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 - name: skipComponentGovernanceDetection value: true - - name: ENABLE_TERRAPIN - value: false + - name: NPM_REGISTRY + value: 'none' + - name: VSCODE_CIBUILD + value: ${{ in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') }} - name: VSCODE_PUBLISH value: false - name: VSCODE_QUALITY @@ -29,164 +22,178 @@ 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_BUILD_TUNNEL_CLI: false + 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_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_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_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_BUILD_TUNNEL_CLI: false + 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_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_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_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_BUILD_TUNNEL_CLI: false + 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-test.yml - parameters: - 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-test.yml - parameters: - 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-test.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: true + - job: LinuxCLI + displayName: Linux (CLI) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + steps: + - template: cli/test.yml + + - ${{ 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-11 + # 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-11 + # 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-11 + # 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 3cc4fc399d9..ded4d810b69 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -25,10 +25,10 @@ parameters: - exploration - insider - stable - - name: ENABLE_TERRAPIN - displayName: "Enable Terrapin" - type: boolean - default: true + - name: NPM_REGISTRY + displayName: "Custom NPM Registry" + type: string + default: 'https://pkgs.dev.azure.com/monacotools/Monaco/_packaging/vscode/npm/registry/' - name: VSCODE_BUILD_WIN32 displayName: "đŸŽ¯ Windows x64" type: boolean @@ -77,6 +77,10 @@ parameters: displayName: "đŸŽ¯ Web" type: boolean default: true + - name: VSCODE_BUILD_TUNNEL_CLI + displayName: "Build Tunnel CLI" + type: boolean + default: true - name: VSCODE_PUBLISH displayName: "Publish to builds.code.visualstudio.com" type: boolean @@ -101,16 +105,18 @@ parameters: variables: - name: VSCODE_DISTRO_REF value: ${{ parameters.VSCODE_DISTRO_REF }} - - name: ENABLE_TERRAPIN - value: ${{ eq(parameters.ENABLE_TERRAPIN, true) }} + - name: NPM_REGISTRY + value: ${{ parameters.NPM_REGISTRY }} - name: VSCODE_QUALITY value: ${{ parameters.VSCODE_QUALITY }} - 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 @@ -169,13 +175,147 @@ stages: parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: + - stage: CompileCLI + dependsOn: [] + jobs: + - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }}: + - job: LinuxX64 + pool: vscode-1es-linux + steps: + - template: ./linux/cli-build-linux.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_LINUX: ${{ parameters.VSCODE_BUILD_LINUX }} + VSCODE_BUILD_LINUX_ALPINE: ${{ parameters.VSCODE_BUILD_LINUX_ALPINE }} + + - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true)) }}: + - job: LinuxGnuARM + pool: vscode-1es-linux + steps: + - template: ./linux/cli-build-linux.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_LINUX_ARMHF: ${{ parameters.VSCODE_BUILD_LINUX_ARMHF }} + VSCODE_BUILD_LINUX_ARM64: ${{ parameters.VSCODE_BUILD_LINUX_ARM64 }} + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: + - job: LinuxAlpineARM64 + pool: vscode-1es-linux-20.04-arm64 + steps: + - task: NodeTool@0 + displayName: Install Node.js + inputs: + versionSpec: 16.x + - script: | + set -e + npm install -g yarn + displayName: Install yarn + - template: ./linux/cli-build-linux.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_LINUX_ALPINE_ARM64: ${{ parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64 }} + + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - job: MacOSX64 + pool: + vmImage: macOS-11 + steps: + - template: ./darwin/cli-build-darwin.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_MACOS: ${{ parameters.VSCODE_BUILD_MACOS }} + + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - job: MacOSARM64 + pool: + vmImage: macOS-11 + steps: + - template: ./darwin/cli-build-darwin.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_MACOS_ARM64: ${{ parameters.VSCODE_BUILD_MACOS_ARM64 }} + + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - job: WindowsX64 + pool: vscode-1es-windows + steps: + - template: ./win32/cli-build-win32.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }} + + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - job: WindowsARM64 + pool: vscode-1es-windows + steps: + - template: ./win32/cli-build-win32.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} + + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: + - job: WindowsX86 + pool: vscode-1es-windows + steps: + - template: ./win32/cli-build-win32.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_WIN32_32BIT: ${{ parameters.VSCODE_BUILD_WIN32_32BIT }} + - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}: - stage: Windows dependsOn: - Compile + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: + - CompileCLI pool: vscode-1es-windows jobs: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - ${{ 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_BUILD_TUNNEL_CLI: false + 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_BUILD_TUNNEL_CLI: false + 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_BUILD_TUNNEL_CLI: false + 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 timeoutInMinutes: 120 variables: @@ -183,7 +323,12 @@ stages: steps: - template: win32/product-build-win32.yml parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} + 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 and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true)) }}: - job: Windows32 @@ -193,7 +338,12 @@ stages: steps: - template: win32/product-build-win32.yml parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} + 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 and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}: - job: WindowsARM64 @@ -203,7 +353,22 @@ stages: steps: - template: win32/product-build-win32.yml parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false + + - ${{ if and(eq(variables['VSCODE_PUBLISH'], true), eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true)) }}: + - job: windowsCLISign + timeoutInMinutes: 90 + steps: + - template: win32/product-build-win32-cli-sign.yml + parameters: + VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }} + VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} + VSCODE_BUILD_WIN32_32BIT: ${{ parameters.VSCODE_BUILD_WIN32_32BIT }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}: - stage: LinuxServerDependencies @@ -235,9 +400,61 @@ stages: dependsOn: - Compile - LinuxServerDependencies + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: + - CompileCLI pool: vscode-1es-linux jobs: - - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: + - ${{ 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_BUILD_TUNNEL_CLI: false + 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_BUILD_TUNNEL_CLI: false + 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_BUILD_TUNNEL_CLI: false + 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 container: vscode-bionic-x64 variables: @@ -247,7 +464,12 @@ stages: steps: - template: linux/product-build-linux-client.yml parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} + 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 and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX, true), ne(variables['VSCODE_PUBLISH'], 'false')) }}: - job: LinuxSnap @@ -268,7 +490,12 @@ stages: steps: - template: linux/product-build-linux-client.yml parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false # TODO@joaomoreno: We don't ship ARM snaps for now - ${{ if and(false, eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true)) }}: @@ -290,7 +517,12 @@ stages: steps: - template: linux/product-build-linux-client.yml parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false # TODO@joaomoreno: We don't ship ARM snaps for now - ${{ if and(false, eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true)) }}: @@ -318,39 +550,92 @@ 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: - Compile + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: + - CompileCLI pool: - vmImage: macOS-latest + vmImage: macOS-11 variables: BUILDSECMON_OPT_IN: true jobs: - - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - job: macOSTest + - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: + - job: macOSUnitTest + displayName: Unit Tests timeoutInMinutes: 90 variables: VSCODE_ARCH: x64 steps: - - template: darwin/product-build-darwin-test.yml + - template: darwin/product-build-darwin.yml parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false + 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_BUILD_TUNNEL_CLI: false + 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_BUILD_TUNNEL_CLI: false + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: true - - ${{ if eq(variables['VSCODE_CIBUILD'], false) }}: - - job: macOS + - ${{ 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_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} + 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_BUILD_TUNNEL_CLI: false + 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 @@ -360,6 +645,15 @@ stages: steps: - template: darwin/product-build-darwin-sign.yml + - ${{ if and(eq(variables['VSCODE_PUBLISH'], true), eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true)) }}: + - job: macOSCLISign + timeoutInMinutes: 90 + steps: + - template: darwin/product-build-darwin-cli-sign.yml + parameters: + VSCODE_BUILD_MACOS: ${{ parameters.VSCODE_BUILD_MACOS }} + VSCODE_BUILD_MACOS_ARM64: ${{ parameters.VSCODE_BUILD_MACOS_ARM64 }} + - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}: - job: macOSARM64 timeoutInMinutes: 90 @@ -367,7 +661,15 @@ stages: VSCODE_ARCH: arm64 steps: - template: darwin/product-build-darwin.yml - - ${{ if eq(variables['VSCODE_CIBUILD'], false) }}: + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false + + - ${{ if eq(variables['VSCODE_PUBLISH'], true) }}: - job: macOSARM64Sign dependsOn: - macOSARM64 @@ -387,7 +689,8 @@ stages: VSCODE_ARCH: universal steps: - template: darwin/product-build-darwin-universal.yml - - ${{ if eq(variables['VSCODE_CIBUILD'], false) }}: + + - ${{ if eq(variables['VSCODE_PUBLISH'], true) }}: - job: macOSUniversalSign dependsOn: - macOSUniversal @@ -397,6 +700,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: @@ -412,13 +728,33 @@ stages: steps: - template: product-publish.yml + - ${{ if and(parameters.VSCODE_RELEASE, eq(parameters.VSCODE_DISTRO_REF, ' ')) }}: + - stage: ApproveRelease + dependsOn: [] # run in parallel to compile stage + pool: vscode-1es-linux + jobs: + - deployment: ApproveRelease + displayName: "Approve Release" + environment: "vscode" + variables: + skipComponentGovernanceDetection: true + strategy: + runOnce: + deploy: + steps: + - checkout: none + - ${{ if or(and(parameters.VSCODE_RELEASE, eq(parameters.VSCODE_DISTRO_REF, ' ')), and(in(parameters.VSCODE_QUALITY, 'insider', 'exploration'), eq(variables['VSCODE_SCHEDULEDBUILD'], true))) }}: - stage: Release dependsOn: - Publish + - ${{ if and(parameters.VSCODE_RELEASE, eq(parameters.VSCODE_DISTRO_REF, ' ')) }}: + - ApproveRelease pool: vscode-1es-linux jobs: - job: ReleaseBuild displayName: Release Build steps: - template: product-release.yml + parameters: + VSCODE_RELEASE: ${{ parameters.VSCODE_RELEASE }} diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 1fd9b0441de..9da22cba292 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -7,45 +7,18 @@ steps: inputs: versionSpec: "16.x" - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - KeyVaultName: vscode - SecretsFilter: "github-distro-mixin-password" + - template: ./mixin-distro-posix.yml + parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF - - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF - echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - git checkout FETCH_HEAD - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit - - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") - displayName: Merge distro + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry - script: | mkdir -p .build - node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH > .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 +29,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 @@ -64,11 +44,17 @@ steps: - 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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication - script: | set -e @@ -79,7 +65,7 @@ steps: - script: | set -e - for i in {1..3}; do # try 3 times, for Terrapin + for i in {1..3}; do # try 3 times yarn --frozen-lockfile --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 @@ -94,6 +80,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 @@ -103,75 +96,85 @@ steps: displayName: Create node_modules archive - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - # Mixin must run before optimize, because the CSS loader will inline small SVGs - - script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality + # Mixin must run before optimize, because the CSS loader will inline small SVGs + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality - script: | set -e - yarn npm-run-all -lp core-ci extensions-ci hygiene eslint valid-layers-check + yarn npm-run-all -lp core-ci extensions-ci hygiene eslint valid-layers-check vscode-dts-compile-check tsec-compile-check env: 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 eq(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + yarn --cwd build compile + ./.github/workflows/check-clean-git-state.sh + displayName: Check /build/ folder - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureCLI@2 - inputs: - azureSubscription: "vscode-builds-subscription" - scriptType: pscore - scriptLocation: inlineScript - addSpnToEnvironment: true - inlineScript: | - Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId" - Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId" - Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" + - 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 - AZURE_STORAGE_ACCOUNT="ticino" \ - AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ - AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ - AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ - node build/azure-pipelines/upload-sourcemaps - displayName: Upload sourcemaps + - task: AzureCLI@2 + inputs: + azureSubscription: "vscode-builds-subscription" + scriptType: pscore + scriptLocation: inlineScript + addSpnToEnvironment: true + inlineScript: | + Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId" + Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId" + Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set - - ./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 - - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz - artifactName: Compilation - displayName: Publish compilation artifact + - script: | + set -e + AZURE_STORAGE_ACCOUNT="ticino" \ + AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ + AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ + AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ + node build/azure-pipelines/upload-sourcemaps + displayName: Upload sourcemaps - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn download-builtin-extensions-cg - displayName: Built-in extensions component details + - script: | + set - + ./build/azure-pipelines/common/extract-telemetry.sh + displayName: Extract Telemetry - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: "Component Detection" - inputs: - sourceScanPath: $(Build.SourcesDirectory) - continueOnError: true + - 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') }}: + - task: PublishPipelineArtifact@1 + inputs: + targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz + artifactName: Compilation + displayName: Publish compilation artifact + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn download-builtin-extensions-cg + displayName: Built-in extensions component details + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: "Component Detection" + inputs: + sourceScanPath: $(Build.SourcesDirectory) + continueOnError: true diff --git a/build/azure-pipelines/product-publish.ps1 b/build/azure-pipelines/product-publish.ps1 index 5abfed48dca..4e47d7d6cb2 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 { @@ -61,12 +62,15 @@ do { if($set.Add($artifactName)) { Write-Host "Processing artifact: '$artifactName. Downloading from: $($_.resource.downloadUrl)" + $extractPath = "$env:AGENT_TEMPDIRECTORY/$artifactName.zip" try { - Invoke-RestMethod $_.resource.downloadUrl -OutFile "$env:AGENT_TEMPDIRECTORY/$artifactName.zip" -Headers @{ + Invoke-RestMethod $_.resource.downloadUrl -OutFile $extractPath -Headers @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" - } -MaximumRetryCount 5 -RetryIntervalSec 1 | Out-Null + } -MaximumRetryCount 5 -RetryIntervalSec 1 -TimeoutSec 300 | Out-Null - Expand-Archive -Path "$env:AGENT_TEMPDIRECTORY/$artifactName.zip" -DestinationPath $env:AGENT_TEMPDIRECTORY | Out-Null + Write-Host "Extracting artifact: '$extractPath'" + + Expand-Archive -Path $extractPath -DestinationPath $env:AGENT_TEMPDIRECTORY | Out-Null } catch { Write-Warning $_ $set.Remove($artifactName) | Out-Null @@ -75,6 +79,13 @@ do { $null,$product,$os,$arch,$type = $artifactName -split '_' $asset = Get-ChildItem -rec "$env:AGENT_TEMPDIRECTORY/$artifactName" + + if ($asset.Size -ne $_.resource.properties.artifactsize) { + Write-Warning "Artifact size mismatch for '$artifactName'. Expected: $($_.resource.properties.artifactsize). Actual: $($asset.Size)" + $set.Remove($artifactName) | Out-Null + continue + } + Write-Host "Processing artifact with the following values:" # turning in into an object just to log nicely @{ 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/product-release.yml b/build/azure-pipelines/product-release.yml index a1086945595..8be900a9b41 100644 --- a/build/azure-pipelines/product-release.yml +++ b/build/azure-pipelines/product-release.yml @@ -1,3 +1,7 @@ +parameters: + - name: VSCODE_RELEASE + type: boolean + steps: - task: NodeTool@0 inputs: @@ -20,4 +24,4 @@ steps: AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ - node build/azure-pipelines/common/releaseBuild.js + node build/azure-pipelines/common/releaseBuild.js ${{ parameters.VSCODE_RELEASE }} diff --git a/build/azure-pipelines/publish-types/check-version.js b/build/azure-pipelines/publish-types/check-version.js index b45ad3f4cc0..34779085a79 100644 --- a/build/azure-pipelines/publish-types/check-version.js +++ b/build/azure-pipelines/publish-types/check-version.js @@ -1,8 +1,8 @@ +"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 }); const cp = require("child_process"); let tag = ''; diff --git a/build/azure-pipelines/publish-types/check-version.ts b/build/azure-pipelines/publish-types/check-version.ts index 137e535353a..35c5a511593 100644 --- a/build/azure-pipelines/publish-types/check-version.ts +++ b/build/azure-pipelines/publish-types/check-version.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as cp from 'child_process'; let tag = ''; diff --git a/build/azure-pipelines/publish-types/update-types.js b/build/azure-pipelines/publish-types/update-types.js index e22911b8470..facece095c3 100644 --- a/build/azure-pipelines/publish-types/update-types.js +++ b/build/azure-pipelines/publish-types/update-types.js @@ -1,8 +1,8 @@ +"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 }); const fs = require("fs"); const cp = require("child_process"); diff --git a/build/azure-pipelines/publish-types/update-types.ts b/build/azure-pipelines/publish-types/update-types.ts index 7ccd976dba5..a727647e64a 100644 --- a/build/azure-pipelines/publish-types/update-types.ts +++ b/build/azure-pipelines/publish-types/update-types.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as fs from 'fs'; import * as cp from 'child_process'; import * as path from 'path'; diff --git a/build/azure-pipelines/sdl-scan.yml b/build/azure-pipelines/sdl-scan.yml index f6a44d4862b..460283240e8 100644 --- a/build/azure-pipelines/sdl-scan.yml +++ b/build/azure-pipelines/sdl-scan.yml @@ -2,10 +2,10 @@ trigger: none pr: none parameters: - - name: ENABLE_TERRAPIN - displayName: "Enable Terrapin" - type: boolean - default: true + - name: NPM_REGISTRY + displayName: "Custom NPM Registry" + type: string + default: "https://pkgs.dev.azure.com/monacotools/Monaco/_packaging/vscode/npm/registry/" - name: SCAN_WINDOWS displayName: "Scan Windows" type: boolean @@ -16,8 +16,8 @@ parameters: default: false variables: - - name: ENABLE_TERRAPIN - value: ${{ eq(parameters.ENABLE_TERRAPIN, true) }} + - name: NPM_REGISTRY + value: ${{ parameters.NPM_REGISTRY }} - name: SCAN_WINDOWS value: ${{ eq(parameters.SCAN_WINDOWS, true) }} - name: SCAN_LINUX @@ -83,11 +83,24 @@ stages: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { npx https://aka.ms/enablesecurefeed standAlone } - timeoutInMinutes: 5 - retryCountOnTaskFailure: 3 - condition: and(succeeded(), eq(variables['ENABLE_TERRAPIN'], 'true')) - displayName: Switch to Terrapin packages + exec { npm config set registry "$env:NPM_REGISTRY" --location=project } + exec { npm config set always-auth=true --location=project } + exec { yarn config set registry "$env:NPM_REGISTRY" } + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/setup-npm-registry.js $env:NPM_REGISTRY } + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry - task: Semmle@1 inputs: @@ -184,15 +197,25 @@ stages: - 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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication + + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry - script: | set -e - for i in {1..3}; do # try 3 times, for Terrapin + for i in {1..3}; do # try 3 times yarn --cwd build --frozen-lockfile --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 @@ -225,7 +248,7 @@ stages: export VSCODE_REMOTE_CXX=$(which g++) fi - for i in {1..3}; do # try 3 times, for Terrapin + for i in {1..3}; do # try 3 times yarn --frozen-lockfile --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 diff --git a/build/azure-pipelines/upload-cdn.js b/build/azure-pipelines/upload-cdn.js index 1bd3ed6f5fd..5a410547456 100644 --- a/build/azure-pipelines/upload-cdn.js +++ b/build/azure-pipelines/upload-cdn.js @@ -1,8 +1,8 @@ +"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 }); const es = require("event-stream"); const Vinyl = require("vinyl"); diff --git a/build/azure-pipelines/upload-cdn.ts b/build/azure-pipelines/upload-cdn.ts index 9ac656e7c26..ddb03c1e839 100644 --- a/build/azure-pipelines/upload-cdn.ts +++ b/build/azure-pipelines/upload-cdn.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as es from 'event-stream'; import * as Vinyl from 'vinyl'; import * as vfs from 'vinyl-fs'; diff --git a/build/azure-pipelines/upload-configuration.js b/build/azure-pipelines/upload-configuration.js index 8be7f4492cc..7ee4c8370ce 100644 --- a/build/azure-pipelines/upload-configuration.js +++ b/build/azure-pipelines/upload-configuration.js @@ -1,8 +1,8 @@ +"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.getSettingsSearchBuildId = exports.shouldSetupSettingsSearch = void 0; const path = require("path"); @@ -52,7 +52,7 @@ function generateVSCodeConfigurationTask() { const timer = setTimeout(() => { codeProc.kill(); reject(new Error('export-default-configuration process timed out')); - }, 30 * 1000); + }, 60 * 1000); codeProc.on('error', err => { clearTimeout(timer); reject(err); diff --git a/build/azure-pipelines/upload-configuration.ts b/build/azure-pipelines/upload-configuration.ts index 49bc00fc46f..1455cfca78f 100644 --- a/build/azure-pipelines/upload-configuration.ts +++ b/build/azure-pipelines/upload-configuration.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as path from 'path'; import * as os from 'os'; import * as cp from 'child_process'; @@ -63,7 +61,7 @@ function generateVSCodeConfigurationTask(): Promise { const timer = setTimeout(() => { codeProc.kill(); reject(new Error('export-default-configuration process timed out')); - }, 30 * 1000); + }, 60 * 1000); codeProc.on('error', err => { clearTimeout(timer); diff --git a/build/azure-pipelines/upload-nlsmetadata.js b/build/azure-pipelines/upload-nlsmetadata.js index a17b8e71267..c92cd277d85 100644 --- a/build/azure-pipelines/upload-nlsmetadata.js +++ b/build/azure-pipelines/upload-nlsmetadata.js @@ -1,14 +1,16 @@ +"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 }); const es = require("event-stream"); const vfs = require("vinyl-fs"); const merge = require("gulp-merge-json"); const gzip = require("gulp-gzip"); const identity_1 = require("@azure/identity"); +const path = require("path"); +const fs_1 = require("fs"); const azure = require('gulp-azure-storage'); const commit = process.env['VSCODE_DISTRO_COMMIT'] || process.env['BUILD_SOURCEVERSION']; const credential = new identity_1.ClientSecretCredential(process.env['AZURE_TENANT_ID'], process.env['AZURE_CLIENT_ID'], process.env['AZURE_CLIENT_SECRET']); @@ -18,8 +20,8 @@ function main() { .pipe(merge({ fileName: 'combined.nls.metadata.json', jsonSpace: '', + concatArrays: true, edit: (parsedJson, file) => { - let key; if (file.base === 'out-vscode-web-min') { return { vscode: parsedJson }; } @@ -63,7 +65,11 @@ function main() { break; } } - key = 'vscode.' + file.relative.split('/')[0]; + // Get extension id and use that as the key + const folderPath = path.join(file.base, file.relative.split('/')[0]); + const manifest = (0, fs_1.readFileSync)(path.join(folderPath, 'package.json'), 'utf-8'); + const manifestJson = JSON.parse(manifest); + const key = manifestJson.publisher + '.' + manifestJson.name; return { [key]: parsedJson }; }, })) diff --git a/build/azure-pipelines/upload-nlsmetadata.ts b/build/azure-pipelines/upload-nlsmetadata.ts index f1d5b5f4d8b..4749e1f9605 100644 --- a/build/azure-pipelines/upload-nlsmetadata.ts +++ b/build/azure-pipelines/upload-nlsmetadata.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as es from 'event-stream'; import * as Vinyl from 'vinyl'; import * as vfs from 'vinyl-fs'; import * as merge from 'gulp-merge-json'; import * as gzip from 'gulp-gzip'; import { ClientSecretCredential } from '@azure/identity'; +import path = require('path'); +import { readFileSync } from 'fs'; const azure = require('gulp-azure-storage'); const commit = process.env['VSCODE_DISTRO_COMMIT'] || process.env['BUILD_SOURCEVERSION']; @@ -33,8 +33,8 @@ function main(): Promise { .pipe(merge({ fileName: 'combined.nls.metadata.json', jsonSpace: '', + concatArrays: true, edit: (parsedJson, file) => { - let key; if (file.base === 'out-vscode-web-min') { return { vscode: parsedJson }; } @@ -82,7 +82,12 @@ function main(): Promise { break; } } - key = 'vscode.' + file.relative.split('/')[0]; + + // Get extension id and use that as the key + const folderPath = path.join(file.base, file.relative.split('/')[0]); + const manifest = readFileSync(path.join(folderPath, 'package.json'), 'utf-8'); + const manifestJson = JSON.parse(manifest); + const key = manifestJson.publisher + '.' + manifestJson.name; return { [key]: parsedJson }; }, })) @@ -113,4 +118,3 @@ main().catch(err => { console.error(err); process.exit(1); }); - diff --git a/build/azure-pipelines/upload-sourcemaps.js b/build/azure-pipelines/upload-sourcemaps.js index 22e3e28290d..b852cb958eb 100644 --- a/build/azure-pipelines/upload-sourcemaps.js +++ b/build/azure-pipelines/upload-sourcemaps.js @@ -1,8 +1,8 @@ +"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 }); const path = require("path"); const es = require("event-stream"); diff --git a/build/azure-pipelines/upload-sourcemaps.ts b/build/azure-pipelines/upload-sourcemaps.ts index e78e783c064..1f76c4c73f4 100644 --- a/build/azure-pipelines/upload-sourcemaps.ts +++ b/build/azure-pipelines/upload-sourcemaps.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as path from 'path'; import * as es from 'event-stream'; import * as Vinyl from 'vinyl'; diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index fa07a82305d..092b3a13aff 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -46,9 +46,14 @@ steps: git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") displayName: Merge distro + - script: node build/setup-npm-registry.js $NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry + - script: | mkdir -p .build - node build/azure-pipelines/common/computeNodeModulesCacheKey.js "web" $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeNodeModulesCacheKey.js "web" > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -58,6 +63,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 @@ -66,15 +77,21 @@ steps: - 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 + npm config set registry "$NPM_REGISTRY" --location=project + npm config set always-auth=true --location=project + yarn config set registry "$NPM_REGISTRY" + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication - script: | set -e - for i in {1..3}; do # try 3 times, for Terrapin + for i in {1..3}; do # try 3 times yarn --frozen-lockfile --check-files && break if [ $i -eq 3 ]; then echo "Yarn failed too many times" >&2 @@ -89,6 +106,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 @@ -163,6 +187,7 @@ steps: cd $ROOT && tar --owner=0 --group=0 -czf $WEB_TARBALL_PATH $WEB_BUILD_NAME displayName: Prepare for publish + condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(Agent.BuildDirectory)/vscode-web.tar.gz artifact: vscode_web_linux_standalone_archive-unsigned diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml new file mode 100644 index 00000000000..d581591730a --- /dev/null +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -0,0 +1,83 @@ +parameters: + - name: VSCODE_BUILD_WIN32 + type: boolean + default: false + - name: VSCODE_BUILD_WIN32_32BIT + type: boolean + default: false + - name: VSCODE_BUILD_WIN32_ARM64 + type: boolean + default: false + - name: VSCODE_QUALITY + type: string + - name: channel + type: string + default: stable + +steps: + - task: Npm@1 + displayName: Download openssl prebuilt + inputs: + command: custom + customCommand: pack @vscode-internal/openssl-prebuilt@0.0.1 + customRegistry: useFeed + customFeed: 'Monaco/openssl-prebuilt' + workingDir: $(Build.ArtifactStagingDirectory) + + - powershell: | + mkdir $(Build.ArtifactStagingDirectory)/openssl + tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.1.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl + displayName: Extract openssl prebuilt + + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-win32.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/azure-pipelines/cli/prepare.js } + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-win32.yml + parameters: + targets: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - x86_64-pc-windows-msvc + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - aarch64-pc-windows-msvc + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: + - i686-pc-windows-msvc + + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: x86_64-pc-windows-msvc + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_x64_cli + VSCODE_CLI_ENV: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-windows-static-md/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-windows-static-md/include + + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: aarch64-pc-windows-msvc + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_arm64_cli + VSCODE_CLI_ENV: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static-md/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static-md/include + + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: i686-pc-windows-msvc + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_ia32_cli + VSCODE_CLI_ENV: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x86-windows-static-md/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x86-windows-static-md/include diff --git a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml new file mode 100644 index 00000000000..b3e7cf3764a --- /dev/null +++ b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml @@ -0,0 +1,29 @@ +parameters: + - name: VSCODE_BUILD_WIN32 + type: boolean + - name: VSCODE_BUILD_WIN32_ARM64 + type: boolean + - name: VSCODE_BUILD_WIN32_32BIT + type: boolean + +steps: + - task: NodeTool@0 + displayName: "Use Node.js" + inputs: + versionSpec: "16.x" + + - pwsh: | + . build/azure-pipelines/win32/exec.ps1 + cd build + exec { yarn } + displayName: Install build dependencies + + - template: ../cli/cli-win32-sign.yml + parameters: + VSCODE_CLI_ARTIFACTS: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - unsigned_vscode_cli_win32_x64_cli + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - unsigned_vscode_cli_win32_arm64_cli + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: + - unsigned_vscode_cli_win32_ia32_cli diff --git a/build/azure-pipelines/win32/product-build-win32-test.yml b/build/azure-pipelines/win32/product-build-win32-test.yml new file mode 100644 index 00000000000..9a17a88bca7 --- /dev/null +++ b/build/azure-pipelines/win32/product-build-win32-test.yml @@ -0,0 +1,251 @@ +parameters: + - name: VSCODE_QUALITY + type: string + - name: VSCODE_RUN_UNIT_TESTS + type: boolean + - name: VSCODE_RUN_INTEGRATION_TESTS + type: boolean + - name: VSCODE_RUN_SMOKE_TESTS + type: boolean + +steps: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + exec { yarn npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" } + displayName: Download Electron and Playwright + + - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: + - ${{ 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 + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn test-node } + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + + - 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: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn gulp ` + compile-extension:configuration-editing ` + compile-extension:css-language-features-server ` + compile-extension:emmet ` + compile-extension:git ` + compile-extension:github-authentication ` + 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 ` + compile-extension:typescript-language-features ` + compile-extension:vscode-api-tests ` + compile-extension:vscode-colorize-tests ` + compile-extension:vscode-test-resolver ` + } + displayName: Build integration tests + + - ${{ 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 + + - 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 + + - 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: | + . build/azure-pipelines/win32/exec.ps1 + exec {.\build\azure-pipelines\win32\listprocesses.bat } + displayName: Diagnostics before smoke test run + continueOnError: true + condition: succeededOrFailed() + + - ${{ 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 + + - script: | + set -e + yarn gulp compile-extension-media + displayName: Build extensions for smoke tests + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn smoketest-no-compile --tracing } + displayName: Run smoke tests (Electron) + 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 + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + exec {.\build\azure-pipelines\win32\listprocesses.bat } + displayName: Diagnostics after smoke test run + continueOnError: true + condition: succeededOrFailed() + + - ${{ if or(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + - task: PublishPipelineArtifact@0 + inputs: + targetPath: .build\crashes + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: crash-dump-windows-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: crash-dump-windows-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: crash-dump-windows-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Crash Reports" + continueOnError: true + condition: failed() + + # In order to properly symbolify above crash reports + # (if any), we need the compiled native modules too + - task: PublishPipelineArtifact@0 + inputs: + targetPath: node_modules + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: node-modules-windows-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: node-modules-windows-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: node-modules-windows-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Node Modules" + continueOnError: true + condition: failed() + + - task: PublishPipelineArtifact@0 + inputs: + targetPath: .build\logs + ${{ if and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: + artifactName: logs-windows-$(VSCODE_ARCH)-integration-$(System.JobAttempt) + ${{ elseif and(eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: + artifactName: logs-windows-$(VSCODE_ARCH)-smoke-$(System.JobAttempt) + ${{ else }}: + artifactName: logs-windows-$(VSCODE_ARCH)-$(System.JobAttempt) + displayName: "Publish Log Files" + continueOnError: true + condition: succeededOrFailed() + + - task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: "*-results.xml" + searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" + condition: succeededOrFailed() diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 7501869b57d..9f62ea0a0c3 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -1,17 +1,23 @@ parameters: + - name: VSCODE_PUBLISH + type: boolean - name: VSCODE_QUALITY type: string - name: VSCODE_RUN_UNIT_TESTS type: boolean - default: true - name: VSCODE_RUN_INTEGRATION_TESTS type: boolean - default: true - name: VSCODE_RUN_SMOKE_TESTS type: boolean - default: true + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean steps: + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 + - task: NodeTool@0 inputs: versionSpec: "16.x" @@ -22,66 +28,82 @@ steps: addToPath: true - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - 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 - - - task: ExtractFiles@1 - displayName: Extract compilation output - inputs: - archiveFilePatterns: "$(Build.ArtifactStagingDirectory)/compilation.tar.gz" - cleanDestinationFolder: false + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII - - exec { git config user.email "vscode@microsoft.com" } - exec { git config user.name "VSCode" } - displayName: Prepare tooling + - task: DownloadPipelineArtifact@2 + inputs: + artifact: Compilation + path: $(Build.ArtifactStagingDirectory) + displayName: Download compilation output - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - - exec { git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $(VSCODE_DISTRO_REF) } - Write-Host "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - exec { git checkout FETCH_HEAD } - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit + - task: ExtractFiles@1 + displayName: Extract compilation output + inputs: + archiveFilePatterns: "$(Build.ArtifactStagingDirectory)/compilation.tar.gz" + cleanDestinationFolder: false - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") } - displayName: Merge distro + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII + + exec { git config user.email "vscode@microsoft.com" } + exec { git config user.name "VSCode" } + displayName: Prepare tooling + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + + exec { git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $(VSCODE_DISTRO_REF) } + Write-Host "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + exec { git checkout FETCH_HEAD } + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit + + - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") } + displayName: Merge distro - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/setup-npm-registry.js $env:NPM_REGISTRY } + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry + + - 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 inputs: - key: "nodeModules | $(Agent.OS) | .build/arch, .build/terrapin, .build/yarnlockhash" + key: "nodeModules | $(Agent.OS) | .build/arch, .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 + - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" @@ -92,11 +114,17 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { 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 + exec { npm config set registry "$env:NPM_REGISTRY" --location=project } + exec { npm config set always-auth=true --location=project } + exec { yarn config set registry "$env:NPM_REGISTRY" } + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM & Yarn + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Authentication - powershell: | . build/azure-pipelines/win32/exec.ps1 @@ -112,6 +140,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" @@ -122,346 +158,229 @@ steps: displayName: Create node_modules archive - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build/azure-pipelines/mixin } - displayName: Mix in quality + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/azure-pipelines/mixin } + displayName: Mix in quality - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - exec { yarn npm-run-all -lp "electron $(VSCODE_ARCH)" } - displayName: Download Electron - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], '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 eq(parameters.VSCODE_QUALITY, 'insider') }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_EXPLORER_APPX_DIR=$(Join-Path $pwd.Path ".build/win32/appx") + exec { node build/win32/explorer-appx-fetcher } + env: + VSCODE_ARCH: "$(VSCODE_ARCH)" + displayName: Download Explorer Sparse Package + condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - ${{ 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)-inno-updater" } - displayName: Prepare Package - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - 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_BUILD_TUNNEL_CLI, true) }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_win32_arm64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_win32_x64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_win32_ia32_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'ia32')) + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $ArtifactName = (gci -Path "$(Build.ArtifactStagingDirectory)/cli" | Select-Object -last 1).FullName + Expand-Archive -Path $ArtifactName -DestinationPath "$(Build.ArtifactStagingDirectory)/cli" + $AppProductJson = Get-Content -Raw -Path "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)\resources\app\product.json" | ConvertFrom-Json + $CliAppName = $AppProductJson.tunnelApplicationName + Move-Item -Path "$(Build.ArtifactStagingDirectory)/cli/code.exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$CliAppName.exe" + displayName: Move VS Code CLI + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-inno-updater" } + displayName: Prepare Package - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build/azure-pipelines/mixin --server } - displayName: Mix in quality - - - 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')) - - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - exec { yarn npm-run-all -lp "playwright-install" } - displayName: Download Playwright - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn gulp ` - compile-extension:css-language-features-server ` - compile-extension:emmet ` - compile-extension:git ` - compile-extension:github-authentication ` - compile-extension:html-language-features-server ` - compile-extension:ipynb ` - compile-extension:json-language-features-server ` - compile-extension:markdown-language-features ` - compile-extension-media ` - compile-extension:microsoft-authentication ` - compile-extension:typescript-language-features ` - compile-extension:vscode-api-tests ` - compile-extension:vscode-colorize-tests ` - compile-extension:vscode-custom-editor-tests ` - compile-extension:vscode-notebook-tests ` - compile-extension:vscode-test-resolver ` - } - displayName: Build integration tests - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - exec {.\build\azure-pipelines\win32\listprocesses.bat } - displayName: Diagnostics before smoke test run - continueOnError: true - condition: and(succeededOrFailed(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ 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 - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - exec {.\build\azure-pipelines\win32\listprocesses.bat } - displayName: Diagnostics after smoke test run - continueOnError: true - condition: and(succeededOrFailed(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - - task: PublishPipelineArtifact@0 - inputs: - artifactName: crash-dump-windows-$(VSCODE_ARCH) - targetPath: .build\crashes - displayName: "Publish Crash Reports" - continueOnError: true - condition: failed() - - # In order to properly symbolify above crash reports - # (if any), we need the compiled native modules too - - task: PublishPipelineArtifact@0 - inputs: - artifactName: node-modules-windows-$(VSCODE_ARCH) - targetPath: node_modules - displayName: "Publish Node Modules" - continueOnError: true - condition: failed() - - - task: PublishPipelineArtifact@0 - inputs: - artifactName: logs-windows-$(VSCODE_ARCH)-$(System.JobAttempt) - targetPath: .build\logs - displayName: "Publish Log Files" - continueOnError: true - condition: and(failed(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - task: PublishTestResults@2 - displayName: Publish Tests Results - inputs: - testResultsFiles: "*-results.xml" - searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" - condition: and(succeededOrFailed(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/azure-pipelines/mixin --server } + displayName: Mix in quality + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: UseDotNet@2 - inputs: - version: 3.x - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - 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') }}: - - task: EsrpClientTool@1 - displayName: Download ESRPClient - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ 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 }} - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $EsrpClientTool = (gci -directory -filter EsrpClientTool_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName - $EsrpCliZip = (gci -recurse -filter esrpcli.*.zip $EsrpClientTool | Select-Object -last 1).FullName - mkdir -p $(Agent.TempDirectory)\esrpcli - Expand-Archive -Path $EsrpCliZip -DestinationPath $(Agent.TempDirectory)\esrpcli - $EsrpCliDllPath = (gci -recurse -filter esrpcli.dll $(Agent.TempDirectory)\esrpcli | Select-Object -last 1).FullName - echo "##vso[task.setvariable variable=EsrpCliDllPath]$EsrpCliDllPath" - displayName: Find ESRP CLI - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: UseDotNet@2 + inputs: + version: 3.x + condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(CodeSigningFolderPath) '*.dll,*.exe,*.node' } - displayName: Codesign - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: EsrpClientTool@1 + displayName: Download ESRPClient - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-archive" } - displayName: Package archive - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $EsrpClientTool = (gci -directory -filter EsrpClientTool_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName + $EsrpCliZip = (gci -recurse -filter esrpcli.*.zip $EsrpClientTool | Select-Object -last 1).FullName + mkdir -p $(Agent.TempDirectory)\esrpcli + Expand-Archive -Path $EsrpCliZip -DestinationPath $(Agent.TempDirectory)\esrpcli + $EsrpCliDllPath = (gci -recurse -filter esrpcli.dll $(Agent.TempDirectory)\esrpcli | Select-Object -last 1).FullName + echo "##vso[task.setvariable variable=EsrpCliDllPath]$EsrpCliDllPath" + displayName: Find ESRP CLI - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:ESRPPKI = "$(ESRP-PKI)" - $env:ESRPAADUsername = "$(esrp-aad-username)" - $env:ESRPAADPassword = "$(esrp-aad-password)" - exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-system-setup" --sign } - exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-user-setup" --sign } - displayName: Package setups - 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\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(CodeSigningFolderPath) '*.dll,*.exe,*.node' } + displayName: Codesign - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - .\build\azure-pipelines\win32\prepare-publish.ps1 - displayName: Publish - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if and(eq(parameters.VSCODE_QUALITY, 'insider'), eq(parameters.VSCODE_PUBLISH, true)) }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows-appx $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(CodeSigningFolderPath) '*.appx' } + displayName: Codesign context menu appx package - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\archive\$(ARCHIVE_NAME) - artifact: vscode_client_win32_$(VSCODE_ARCH)_archive - displayName: Publish archive - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-archive" } + displayName: Package archive - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\system-setup\$(SYSTEM_SETUP_NAME) - artifact: vscode_client_win32_$(VSCODE_ARCH)_setup - displayName: Publish system setup - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:ESRPPKI = "$(ESRP-PKI)" + $env:ESRPAADUsername = "$(esrp-aad-username)" + $env:ESRPAADPassword = "$(esrp-aad-password)" + exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-system-setup" --sign } + exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-user-setup" --sign } + displayName: Package setups - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\user-setup\$(USER_SETUP_NAME) - artifact: vscode_client_win32_$(VSCODE_ARCH)_user-setup - displayName: Publish user setup - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + .\build\azure-pipelines\win32\prepare-publish.ps1 + displayName: Publish - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(System.DefaultWorkingDirectory)\.build\vscode-server-win32-$(VSCODE_ARCH).zip - artifact: vscode_server_win32_$(VSCODE_ARCH)_archive - displayName: Publish server archive - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (client) + inputs: + BuildDropPath: $(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH) + PackageName: Visual Studio Code - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(System.DefaultWorkingDirectory)\.build\vscode-server-win32-$(VSCODE_ARCH)-web.zip - artifact: vscode_web_win32_$(VSCODE_ARCH)_archive - displayName: Publish web server archive - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (client) + artifact: vscode_client_win32_$(VSCODE_ARCH)_sbom - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (client) - inputs: - BuildDropPath: $(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH) - PackageName: Visual Studio Code - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (server) + inputs: + BuildDropPath: $(agent.builddirectory)/vscode-server-win32-$(VSCODE_ARCH) + PackageName: Visual Studio Code Server + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (client) - artifact: vscode_client_win32_$(VSCODE_ARCH)_sbom - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(agent.builddirectory)/vscode-server-win32-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (server) + artifact: vscode_server_win32_$(VSCODE_ARCH)_sbom + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (server) - inputs: - BuildDropPath: $(agent.builddirectory)/vscode-server-win32-$(VSCODE_ARCH) - PackageName: Visual Studio Code Server - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\archive\$(ARCHIVE_NAME) + artifact: vscode_client_win32_$(VSCODE_ARCH)_archive + displayName: Publish archive - - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - publish: $(agent.builddirectory)/vscode-server-win32-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (server) - artifact: vscode_server_win32_$(VSCODE_ARCH)_sbom - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\system-setup\$(SYSTEM_SETUP_NAME) + artifact: vscode_client_win32_$(VSCODE_ARCH)_setup + displayName: Publish system setup + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\user-setup\$(USER_SETUP_NAME) + artifact: vscode_client_win32_$(VSCODE_ARCH)_user-setup + displayName: Publish user setup + condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(System.DefaultWorkingDirectory)\.build\vscode-server-win32-$(VSCODE_ARCH).zip + artifact: vscode_server_win32_$(VSCODE_ARCH)_archive + displayName: Publish server archive + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) + + - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: + - publish: $(System.DefaultWorkingDirectory)\.build\vscode-server-win32-$(VSCODE_ARCH)-web.zip + artifact: vscode_web_win32_$(VSCODE_ARCH)_archive + displayName: Publish web server archive + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) diff --git a/build/builtin/main.js b/build/builtin/main.js index b1842e9a595..f4dbc6e8325 100644 --- a/build/builtin/main.js +++ b/build/builtin/main.js @@ -30,8 +30,7 @@ app.once('ready', () => { webPreferences: { nodeIntegration: true, contextIsolation: false, - enableWebSQL: false, - nativeWindowOpen: true + enableWebSQL: false } }); window.setMenuBarVisibility(false); diff --git a/build/darwin/create-universal-app.js b/build/darwin/create-universal-app.js index 197bf5b2f1b..750366e752d 100644 --- a/build/darwin/create-universal-app.js +++ b/build/darwin/create-universal-app.js @@ -1,8 +1,8 @@ +"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 }); const vscode_universal_bundler_1 = require("vscode-universal-bundler"); const cross_spawn_promise_1 = require("@malept/cross-spawn-promise"); @@ -39,7 +39,7 @@ async function main() { outAppPath, force: true }); - let productJson = await fs.readJson(productJsonPath); + const productJson = await fs.readJson(productJsonPath); Object.assign(productJson, { darwinUniversalAssetId: 'darwin-universal' }); diff --git a/build/darwin/create-universal-app.ts b/build/darwin/create-universal-app.ts index 7d145eaec71..5f4b3170532 100644 --- a/build/darwin/create-universal-app.ts +++ b/build/darwin/create-universal-app.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import { makeUniversalApp } from 'vscode-universal-bundler'; import { spawn } from '@malept/cross-spawn-promise'; import * as fs from 'fs-extra'; @@ -45,7 +43,7 @@ async function main() { force: true }); - let productJson = await fs.readJson(productJsonPath); + const productJson = await fs.readJson(productJsonPath); Object.assign(productJson, { darwinUniversalAssetId: 'darwin-universal' }); diff --git a/build/darwin/sign.js b/build/darwin/sign.js index 02b0e1f052e..ef6bef395e4 100644 --- a/build/darwin/sign.js +++ b/build/darwin/sign.js @@ -1,8 +1,8 @@ +"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 }); const codesign = require("electron-osx-sign"); const path = require("path"); @@ -26,6 +26,7 @@ async function main() { const helperAppBaseName = product.nameShort; const gpuHelperAppName = helperAppBaseName + ' Helper (GPU).app'; const rendererHelperAppName = helperAppBaseName + ' Helper (Renderer).app'; + const pluginHelperAppName = helperAppBaseName + ' Helper (Plugin).app'; const infoPlistPath = path.resolve(appRoot, appName, 'Contents', 'Info.plist'); const defaultOpts = { app: path.join(appRoot, appName), @@ -45,7 +46,8 @@ async function main() { // TODO(deepak1556): Incorrectly declared type in electron-osx-sign ignore: (filePath) => { return filePath.includes(gpuHelperAppName) || - filePath.includes(rendererHelperAppName); + filePath.includes(rendererHelperAppName) || + filePath.includes(pluginHelperAppName); } }; const gpuHelperOpts = { @@ -60,6 +62,12 @@ async function main() { entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'), 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'), }; + const pluginHelperOpts = { + ...defaultOpts, + app: path.join(appFrameworkPath, pluginHelperAppName), + entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'), + 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'), + }; // Only overwrite plist entries for x64 and arm64 builds, // universal will get its copy from the x64 build. if (arch !== 'universal') { @@ -87,6 +95,7 @@ async function main() { } await codesign.signAsync(gpuHelperOpts); await codesign.signAsync(rendererHelperOpts); + await codesign.signAsync(pluginHelperOpts); await codesign.signAsync(appOpts); } if (require.main === module) { diff --git a/build/darwin/sign.ts b/build/darwin/sign.ts index 9b0a9f75afc..7490d45eaed 100644 --- a/build/darwin/sign.ts +++ b/build/darwin/sign.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as codesign from 'electron-osx-sign'; import * as path from 'path'; import * as util from '../lib/util'; @@ -31,6 +29,7 @@ async function main(): Promise { const helperAppBaseName = product.nameShort; const gpuHelperAppName = helperAppBaseName + ' Helper (GPU).app'; const rendererHelperAppName = helperAppBaseName + ' Helper (Renderer).app'; + const pluginHelperAppName = helperAppBaseName + ' Helper (Plugin).app'; const infoPlistPath = path.resolve(appRoot, appName, 'Contents', 'Info.plist'); const defaultOpts: codesign.SignOptions = { @@ -52,7 +51,8 @@ async function main(): Promise { // TODO(deepak1556): Incorrectly declared type in electron-osx-sign ignore: (filePath: string) => { return filePath.includes(gpuHelperAppName) || - filePath.includes(rendererHelperAppName); + filePath.includes(rendererHelperAppName) || + filePath.includes(pluginHelperAppName); } }; @@ -70,6 +70,13 @@ async function main(): Promise { 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'), }; + const pluginHelperOpts: codesign.SignOptions = { + ...defaultOpts, + app: path.join(appFrameworkPath, pluginHelperAppName), + entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'), + 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'), + }; + // Only overwrite plist entries for x64 and arm64 builds, // universal will get its copy from the x64 build. if (arch !== 'universal') { @@ -98,6 +105,7 @@ async function main(): Promise { await codesign.signAsync(gpuHelperOpts); await codesign.signAsync(rendererHelperOpts); + await codesign.signAsync(pluginHelperOpts); await codesign.signAsync(appOpts as any); } 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 c2a0a52bdb9..ff8e4ef81b3 100644 --- a/build/filters.js +++ b/build/filters.js @@ -22,6 +22,7 @@ module.exports.all = [ 'scripts/**/*', 'src/**/*', 'test/**/*', + '!cli/**/*', '!out*/**', '!test/**/out/**', '!**/node_modules/**', @@ -39,6 +40,7 @@ module.exports.unicodeFilter = [ '!**/test/**', '!**/*.test.ts', '!**/*.{d.ts,json,md}', + '!**/*.mp3', '!build/win32/**', '!extensions/markdown-language-features/notebook-out/*.js', @@ -48,7 +50,6 @@ module.exports.unicodeFilter = [ '!extensions/typescript-language-features/test-workspace/**', '!extensions/vscode-api-tests/testWorkspace/**', '!extensions/vscode-api-tests/testWorkspace2/**', - '!extensions/vscode-custom-editor-tests/test-workspace/**', '!extensions/**/dist/**', '!extensions/**/out/**', '!extensions/**/snippets/**', @@ -66,10 +67,7 @@ module.exports.indentationFilter = [ '!**/LICENSE.{txt,rtf}', '!LICENSES.chromium.html', '!**/LICENSE', - '!src/vs/nls.js', - '!src/vs/nls.build.js', - '!src/vs/css.js', - '!src/vs/css.build.js', + '!**/*.mp3', '!src/vs/loader.js', '!src/vs/base/browser/dompurify/*', '!src/vs/base/common/marked/marked.js', @@ -85,10 +83,10 @@ module.exports.indentationFilter = [ '!test/monaco/out/**', '!test/smoke/out/**', '!extensions/typescript-language-features/test-workspace/**', + '!extensions/typescript-language-features/resources/walkthroughs/**', '!extensions/markdown-math/notebook-out/**', '!extensions/vscode-api-tests/testWorkspace/**', '!extensions/vscode-api-tests/testWorkspace2/**', - '!extensions/vscode-custom-editor-tests/test-workspace/**', '!build/monaco/**', '!build/win32/**', @@ -141,10 +139,12 @@ module.exports.copyrightFilter = [ '!**/*.cmd', '!**/*.ico', '!**/*.opus', + '!**/*.mp3', '!**/*.icns', '!**/*.xml', '!**/*.sh', '!**/*.zsh', + '!**/*.fish', '!**/*.txt', '!**/*.xpm', '!**/*.opts', diff --git a/build/gulpfile.compile.js b/build/gulpfile.compile.js index c3049784fe4..1424c90e3d0 100644 --- a/build/gulpfile.compile.js +++ b/build/gulpfile.compile.js @@ -9,13 +9,16 @@ const gulp = require('gulp'); const util = require('./lib/util'); const task = require('./lib/task'); const compilation = require('./lib/compilation'); +const optimize = require('./lib/optimize'); // Full compile, including nls and inline sources in sourcemaps, for build const compileBuildTask = task.define('compile-build', task.series( util.rimraf('out-build'), util.buildWebNodePaths('out-build'), - compilation.compileTask('src', 'out-build', true) + compilation.compileApiProposalNamesTask, + compilation.compileTask('src', 'out-build', true), + optimize.optimizeLoaderTask('out-build', 'out-build', true) ) ); gulp.task(compileBuildTask); diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 41dbfe647ae..fb3a148f9a8 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -6,8 +6,9 @@ const gulp = require('gulp'); const path = require('path'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); -const common = require('./lib/optimize'); +const optimize = require('./lib/optimize'); const es = require('event-stream'); const File = require('vinyl'); const i18n = require('./lib/i18n'); @@ -17,34 +18,41 @@ const compilation = require('./lib/compilation'); const monacoapi = require('./lib/monaco-api'); const fs = require('fs'); -let root = path.dirname(__dirname); -let sha1 = util.getVersion(root); -let semver = require('./monaco/package.json').version; -let headerVersion = semver + '(' + sha1 + ')'; +const root = path.dirname(__dirname); +const sha1 = getVersion(root); +const semver = require('./monaco/package.json').version; +const headerVersion = semver + '(' + sha1 + ')'; // Build -let editorEntryPoints = [ +const editorEntryPoints = [ { name: 'vs/editor/editor.main', include: [], exclude: ['vs/css', 'vs/nls'], - prepend: ['out-editor-build/vs/css.js', 'out-editor-build/vs/nls.js'], + prepend: [ + { path: 'out-editor-build/vs/css.js', amdModuleId: 'vs/css' }, + { path: 'out-editor-build/vs/nls.js', amdModuleId: 'vs/nls' } + ], }, { name: 'vs/base/common/worker/simpleWorker', include: ['vs/editor/common/services/editorSimpleWorker'], - prepend: ['vs/loader.js'], - append: ['vs/base/worker/workerMain'], + exclude: ['vs/nls'], + prepend: [ + { path: 'vs/loader.js' }, + { path: 'vs/nls.js', amdModuleId: 'vs/nls' }, + { path: 'vs/base/worker/workerMain.js' } + ], dest: 'vs/base/worker/workerMain.js' } ]; -let editorResources = [ +const editorResources = [ 'out-editor-build/vs/base/browser/ui/codicons/**/*.ttf' ]; -let BUNDLED_FILE_HEADER = [ +const BUNDLED_FILE_HEADER = [ '/*!-----------------------------------------------------------', ' * Copyright (c) Microsoft Corporation. All rights reserved.', ' * Version: ' + headerVersion, @@ -79,26 +87,29 @@ const extractEditorSrcTask = task.define('extract-editor-src', () => { const compileEditorAMDTask = task.define('compile-editor-amd', compilation.compileTask('out-editor-src', 'out-editor-build', true)); -const optimizeEditorAMDTask = task.define('optimize-editor-amd', common.optimizeTask({ - src: 'out-editor-build', - entryPoints: editorEntryPoints, - resources: editorResources, - loaderConfig: { - paths: { - 'vs': 'out-editor-build/vs', - 'vs/css': 'out-editor-build/vs/css.build', - 'vs/nls': 'out-editor-build/vs/nls.build', - 'vscode': 'empty:' +const optimizeEditorAMDTask = task.define('optimize-editor-amd', optimize.optimizeTask( + { + out: 'out-editor', + amd: { + src: 'out-editor-build', + entryPoints: editorEntryPoints, + resources: editorResources, + loaderConfig: { + paths: { + 'vs': 'out-editor-build/vs', + 'vs/css': 'out-editor-build/vs/css.build', + 'vs/nls': 'out-editor-build/vs/nls.build', + 'vscode': 'empty:' + } + }, + header: BUNDLED_FILE_HEADER, + bundleInfo: true, + languages } - }, - bundleLoader: false, - header: BUNDLED_FILE_HEADER, - bundleInfo: true, - out: 'out-editor', - languages: languages -})); + } +)); -const minifyEditorAMDTask = task.define('minify-editor-amd', common.minifyTask('out-editor')); +const minifyEditorAMDTask = task.define('minify-editor-amd', optimize.minifyTask('out-editor')); const createESMSourcesAndResourcesTask = task.define('extract-editor-esm', () => { standalone.createESMSourcesAndResources2({ @@ -109,12 +120,6 @@ const createESMSourcesAndResourcesTask = task.define('extract-editor-esm', () => 'inlineEntryPoint:0.ts', 'inlineEntryPoint:1.ts', 'vs/loader.js', - 'vs/nls.ts', - 'vs/nls.build.js', - 'vs/nls.d.ts', - 'vs/css.js', - 'vs/css.build.js', - 'vs/css.d.ts', 'vs/base/worker/workerMain.ts', ], renames: { @@ -224,7 +229,7 @@ const appendJSToESMImportsTask = task.define('append-js-to-esm-imports', () => { result.push(line); continue; } - let modifiedLine = ( + const modifiedLine = ( line .replace(/^import(.*)\'([^']+)\'/, `import$1'$2.js'`) .replace(/^export \* from \'([^']+)\'/, `export * from '$1.js'`) @@ -239,10 +244,10 @@ const appendJSToESMImportsTask = task.define('append-js-to-esm-imports', () => { * @param {string} contents */ function toExternalDTS(contents) { - let lines = contents.split(/\r\n|\r|\n/); + const lines = contents.split(/\r\n|\r|\n/); let killNextCloseCurlyBrace = false; for (let i = 0; i < lines.length; i++) { - let line = lines[i]; + const line = lines[i]; if (killNextCloseCurlyBrace) { if ('}' === line) { @@ -316,7 +321,7 @@ const finalEditorResourcesTask = task.define('final-editor-resources', () => { // package.json gulp.src('build/monaco/package.json') .pipe(es.through(function (data) { - let json = JSON.parse(data.contents.toString()); + const json = JSON.parse(data.contents.toString()); json.private = false; data.contents = Buffer.from(JSON.stringify(json, null, ' ')); this.emit('data', data); @@ -360,10 +365,10 @@ const finalEditorResourcesTask = task.define('final-editor-resources', () => { return; } - let relativePathToMap = path.relative(path.join(data.relative), path.join('min-maps', data.relative + '.map')); + const relativePathToMap = path.relative(path.join(data.relative), path.join('min-maps', data.relative + '.map')); let strContents = data.contents.toString(); - let newStr = '//# sourceMappingURL=' + relativePathToMap.replace(/\\/g, '/'); + const newStr = '//# sourceMappingURL=' + relativePathToMap.replace(/\\/g, '/'); strContents = strContents.replace(/\/\/# sourceMappingURL=[^ ]+$/, newStr); data.contents = Buffer.from(strContents); @@ -483,13 +488,13 @@ function createTscCompileTask(watch) { cwd: path.join(__dirname, '..'), // stdio: [null, 'pipe', 'inherit'] }); - let errors = []; - let reporter = createReporter('monaco'); + const errors = []; + const reporter = createReporter('monaco'); /** @type {NodeJS.ReadWriteStream | undefined} */ let report; // eslint-disable-next-line no-control-regex - let magic = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; // https://stackoverflow.com/questions/25245716/remove-all-ansi-colors-styles-from-strings + const magic = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; // https://stackoverflow.com/questions/25245716/remove-all-ansi-colors-styles-from-strings child.stdout.on('data', data => { let str = String(data); @@ -502,12 +507,12 @@ function createTscCompileTask(watch) { report.end(); } else if (str) { - let match = /(.*\(\d+,\d+\): )(.*: )(.*)/.exec(str); + const match = /(.*\(\d+,\d+\): )(.*: )(.*)/.exec(str); if (match) { // trying to massage the message so that it matches the gulp-tsb error messages // e.g. src/vs/base/common/strings.ts(663,5): error TS2322: Type '1234' is not assignable to type 'string'. - let fullpath = path.join(root, match[1]); - let message = match[3]; + const fullpath = path.join(root, match[1]); + const message = match[3]; reporter(fullpath + message); } else { reporter(str); diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index ba2606861fd..c0b79bc0f9d 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -12,15 +12,15 @@ const nodeUtil = require('util'); const es = require('event-stream'); const filter = require('gulp-filter'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const watcher = require('./lib/watch'); const createReporter = require('./lib/reporter').createReporter; const glob = require('glob'); const root = path.dirname(__dirname); -const commit = util.getVersion(root); +const commit = getVersion(root); const plumber = require('gulp-plumber'); const ext = require('./lib/extensions'); -const product = require('../product.json'); const extensionsPath = path.join(path.dirname(__dirname), 'extensions'); @@ -47,14 +47,15 @@ const compilations = [ 'gulp/tsconfig.json', 'html-language-features/client/tsconfig.json', 'html-language-features/server/tsconfig.json', - 'image-preview/tsconfig.json', 'ipynb/tsconfig.json', 'jake/tsconfig.json', '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', + 'media-preview/tsconfig.json', 'merge-conflict/tsconfig.json', 'microsoft-authentication/tsconfig.json', 'npm/tsconfig.json', @@ -66,8 +67,6 @@ const compilations = [ 'typescript-language-features/tsconfig.json', 'vscode-api-tests/tsconfig.json', 'vscode-colorize-tests/tsconfig.json', - 'vscode-custom-editor-tests/tsconfig.json', - 'vscode-notebook-tests/tsconfig.json', 'vscode-test-resolver/tsconfig.json' ]; @@ -91,7 +90,7 @@ const tasks = compilations.map(function (tsconfigFile) { const baseUrl = getBaseUrl(out); let headerId, headerOut; - let index = relativeDirname.indexOf('/'); + const index = relativeDirname.indexOf('/'); if (index < 0) { headerId = 'vscode.' + relativeDirname; headerOut = 'out'; @@ -100,7 +99,7 @@ const tasks = compilations.map(function (tsconfigFile) { headerOut = relativeDirname.substr(index + 1) + '/out'; } - function createPipeline(build, emitError) { + function createPipeline(build, emitError, transpileOnly) { const nlsDev = require('vscode-nls-dev'); const tsb = require('./lib/tsb'); const sourcemaps = require('gulp-sourcemaps'); @@ -110,7 +109,7 @@ const tasks = compilations.map(function (tsconfigFile) { overrideOptions.inlineSources = Boolean(build); overrideOptions.base = path.dirname(absolutePath); - const compilation = tsb.create(absolutePath, overrideOptions, false, 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(); @@ -152,6 +151,16 @@ const tasks = compilations.map(function (tsconfigFile) { const cleanTask = task.define(`clean-extension-${name}`, util.rimraf(out)); + const transpileTask = task.define(`transpile-extension:${name}`, task.series(cleanTask, () => { + const pipeline = createPipeline(false, true, true); + const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts'])); + const input = es.merge(nonts, pipeline.tsProjectSrc()); + + return input + .pipe(pipeline()) + .pipe(gulp.dest(out)); + })); + const compileTask = task.define(`compile-extension:${name}`, task.series(cleanTask, () => { const pipeline = createPipeline(false, true); const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts'])); @@ -184,12 +193,16 @@ const tasks = compilations.map(function (tsconfigFile) { })); // Tasks + gulp.task(transpileTask); gulp.task(compileTask); gulp.task(watchTask); - return { compileTask, watchTask, compileBuildTask }; + return { transpileTask, compileTask, watchTask, compileBuildTask }; }); +const transpileExtensionsTask = task.define('transpile-extensions', task.parallel(...tasks.map(t => t.transpileTask))); +gulp.task(transpileExtensionsTask); + const compileExtensionsTask = task.define('compile-extensions', task.parallel(...tasks.map(t => t.compileTask))); gulp.task(compileExtensionsTask); exports.compileExtensionsTask = compileExtensionsTask; @@ -222,8 +235,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.hygiene.js b/build/gulpfile.hygiene.js index a9691fcb0d8..c76fab7abc6 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -16,7 +16,7 @@ function checkPackageJSON(actualPath) { const actual = require(path.join(__dirname, '..', actualPath)); const rootPackageJSON = require('../package.json'); const checkIncluded = (set1, set2) => { - for (let depName in set1) { + for (const depName in set1) { const depVersion = set1[depName]; const rootDepVersion = set2[depName]; if (!rootDepVersion) { diff --git a/build/gulpfile.js b/build/gulpfile.js index 65dda505fa7..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 { 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,14 @@ 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); + // Fast compile for development time const compileClientTask = task.define('compile-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), compileApiProposalNamesTask, compileTask('src', 'out', false))); gulp.task(compileClientTask); diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 54135e9f50d..7475e04d6e5 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -9,8 +9,9 @@ const gulp = require('gulp'); const path = require('path'); const es = require('event-stream'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); -const common = require('./lib/optimize'); +const optimize = require('./lib/optimize'); const product = require('../product.json'); const rename = require('gulp-rename'); const replace = require('gulp-replace'); @@ -30,7 +31,7 @@ const { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileCont const cp = require('child_process'); const REPO_ROOT = path.dirname(__dirname); -const commit = util.getVersion(REPO_ROOT); +const commit = getVersion(REPO_ROOT); const BUILD_ROOT = path.dirname(REPO_ROOT); const REMOTE_FOLDER = path.join(REPO_ROOT, 'remote'); @@ -58,15 +59,10 @@ const serverResources = [ 'out-build/bootstrap-fork.js', 'out-build/bootstrap-amd.js', 'out-build/bootstrap-node.js', - 'out-build/paths.js', // Performance 'out-build/vs/base/common/performance.js', - // main entry points - 'out-build/server-cli.js', - 'out-build/server-main.js', - // Watcher 'out-build/vs/platform/files/**/*.exe', 'out-build/vs/platform/files/**/*.md', @@ -76,12 +72,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/**' ]; @@ -252,7 +250,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa const date = new Date().toISOString(); const productJsonStream = gulp.src(['product.json'], { base: '.' }) - .pipe(json({ commit, date })); + .pipe(json({ commit, date, version })); const license = gulp.src(['remote/LICENSE'], { base: 'remote', allowEmpty: true }); @@ -281,7 +279,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa ].map(resource => gulp.src(resource, { base: '.' }).pipe(rename(resource))); } - let all = es.merge( + const all = es.merge( packageJsonStream, productJsonStream, license, @@ -355,23 +353,42 @@ function tweakProductForServerWeb(product) { ['reh', 'reh-web'].forEach(type => { const optimizeTask = task.define(`optimize-vscode-${type}`, task.series( util.rimraf(`out-vscode-${type}`), - common.optimizeTask({ - src: 'out-build', - entryPoints: _.flatten(type === 'reh' ? serverEntryPoints : serverWithWebEntryPoints), - otherSources: [], - resources: type === 'reh' ? serverResources : serverWithWebResources, - loaderConfig: common.loaderConfig(), - out: `out-vscode-${type}`, - inlineAmdImages: true, - bundleInfo: undefined, - fileContentMapper: createVSCodeWebFileContentMapper('.build/extensions', type === 'reh-web' ? tweakProductForServerWeb(product) : product) - }) + optimize.optimizeTask( + { + out: `out-vscode-${type}`, + amd: { + src: 'out-build', + entryPoints: _.flatten(type === 'reh' ? serverEntryPoints : serverWithWebEntryPoints), + otherSources: [], + resources: type === 'reh' ? serverResources : serverWithWebResources, + loaderConfig: optimize.loaderConfig(), + inlineAmdImages: true, + bundleInfo: undefined, + fileContentMapper: createVSCodeWebFileContentMapper('.build/extensions', type === 'reh-web' ? tweakProductForServerWeb(product) : product) + }, + commonJS: { + src: 'out-build', + entryPoints: [ + 'out-build/server-main.js', + 'out-build/server-cli.js' + ], + platform: 'node', + external: [ + 'minimist', + // TODO: we cannot inline `product.json` because + // it is being changed during build time at a later + // point in time (such as `checksums`) + '../product.json' + ] + } + } + ) )); const minifyTask = task.define(`minify-vscode-${type}`, task.series( optimizeTask, util.rimraf(`out-vscode-${type}-min`), - common.minifyTask(`out-vscode-${type}`, `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`) + optimize.minifyTask(`out-vscode-${type}`, `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`) )); gulp.task(minifyTask); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 268650959cd..d5b4db00073 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'); @@ -17,11 +18,12 @@ const replace = require('gulp-replace'); const filter = require('gulp-filter'); const _ = require('underscore'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const buildfile = require('../src/buildfile'); -const common = require('./lib/optimize'); +const optimize = require('./lib/optimize'); const root = path.dirname(__dirname); -const commit = util.getVersion(root); +const commit = getVersion(root); const packageJson = require('../package.json'); const product = require('../product.json'); const crypto = require('crypto'); @@ -33,6 +35,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([ @@ -43,31 +48,28 @@ const vscodeEntryPoints = _.flatten([ buildfile.workerLanguageDetection, buildfile.workerSharedProcess, buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, buildfile.workbenchDesktop, buildfile.code ]); const vscodeResources = [ - 'out-build/main.js', - 'out-build/cli.js', 'out-build/bootstrap.js', 'out-build/bootstrap-fork.js', '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', - 'out-build/vs/base/common/stripComments.js', - 'out-build/vs/base/node/languagePacks.js', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}', 'out-build/vs/base/browser/ui/codicons/codicon/**', 'out-build/vs/base/parts/sandbox/electron-browser/preload.js', - 'out-build/vs/platform/environment/node/userDataPath.js', '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,23 +78,58 @@ 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-browser/sharedProcess/sharedProcess.js', - 'out-build/vs/code/electron-sandbox/issue/issueReporter.js', - 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.js', '!**/test/**' ]; +// Do not change the order of these files! They will +// be inlined into the target window file in this order +// and they depend on each other in this way. +const windowBootstrapFiles = [ + 'out-build/bootstrap.js', + 'out-build/vs/loader.js', + 'out-build/bootstrap-window.js' +]; + const optimizeVSCodeTask = task.define('optimize-vscode', task.series( util.rimraf('out-vscode'), - common.optimizeTask({ - src: 'out-build', - entryPoints: vscodeEntryPoints, - resources: vscodeResources, - loaderConfig: common.loaderConfig(), - out: 'out-vscode', - bundleInfo: undefined - }) + // Optimize: bundles source files automatically based on + // AMD and CommonJS import statements based on the passed + // in entry points. In addition, concat window related + // bootstrap files into a single file. + optimize.optimizeTask( + { + out: 'out-vscode', + amd: { + src: 'out-build', + entryPoints: vscodeEntryPoints, + resources: vscodeResources, + loaderConfig: optimize.loaderConfig(), + bundleInfo: undefined + }, + commonJS: { + src: 'out-build', + entryPoints: [ + 'out-build/main.js', + 'out-build/cli.js' + ], + platform: 'node', + external: [ + 'electron', + 'minimist', + // TODO: we cannot inline `product.json` because + // it is being changed during build time at a later + // point in time (such as `checksums`) + '../product.json' + ] + }, + manual: [ + { src: [...windowBootstrapFiles, 'out-build/vs/code/electron-sandbox/workbench/workbench.js'], out: 'vs/code/electron-sandbox/workbench/workbench.js' }, + { src: [...windowBootstrapFiles, 'out-build/vs/code/electron-sandbox/issue/issueReporter.js'], out: 'vs/code/electron-sandbox/issue/issueReporter.js' }, + { src: [...windowBootstrapFiles, 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.js'], out: 'vs/code/electron-sandbox/processExplorer/processExplorer.js' }, + { src: [...windowBootstrapFiles, 'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js'], out: 'vs/code/electron-browser/sharedProcess/sharedProcess.js' } + ] + } + ) )); gulp.task(optimizeVSCodeTask); @@ -100,7 +137,7 @@ const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${ const minifyVSCodeTask = task.define('minify-vscode', task.series( optimizeVSCodeTask, util.rimraf('out-vscode-min'), - common.minifyTask('out-vscode', `${sourceMappingURLBase}/core`) + optimize.minifyTask('out-vscode', `${sourceMappingURLBase}/core`) )); gulp.task(minifyVSCodeTask); @@ -122,9 +159,9 @@ gulp.task(core); * @return {Object} A map of paths to checksums. */ function computeChecksums(out, filenames) { - let result = {}; + const result = {}; filenames.forEach(function (filename) { - let fullPath = path.join(process.cwd(), out, filename); + const fullPath = path.join(process.cwd(), out, filename); result[filename] = computeChecksum(fullPath); }); return result; @@ -137,9 +174,9 @@ function computeChecksums(out, filenames) { * @return {string} The checksum for `filename`. */ function computeChecksum(filename) { - let contents = fs.readFileSync(filename); + const contents = fs.readFileSync(filename); - let hash = crypto + const hash = crypto .createHash('md5') .update(contents) .digest('base64') @@ -165,8 +202,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: '.' }) @@ -206,7 +243,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(json(packageJsonUpdates)); const date = new Date().toISOString(); - const productJsonUpdate = { commit, date, checksums }; + const productJsonUpdate = { commit, date, checksums, version }; if (shouldSetupSettingsSearch()) { productJsonUpdate.settingsSearchBuildId = getSettingsSearchBuildId(packageJson); @@ -240,6 +277,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op '**/node-pty/lib/worker/conoutSocketWorker.js', '**/node-pty/lib/shared/conout.js', '**/*.wasm', + '**/node-vsce-sign/bin/*', ], 'node_modules.asar')); let all = es.merge( @@ -331,6 +369,12 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op result = es.merge(result, gulp.src('resources/win32/VisualElementsManifest.xml', { base: 'resources/win32' }) .pipe(rename(product.nameShort + '.VisualElementsManifest.xml'))); + result = es.merge(result, gulp.src('.build/policies/win32/**', { base: '.build/policies/win32' }) + .pipe(rename(f => f.dirname = `policies/${f.dirname}`))); + + if (quality === 'insider') { + result = es.merge(result, gulp.src('.build/win32/appx/**', { base: '.build/win32' })); + } } else if (platform === 'linux') { result = es.merge(result, gulp.src('resources/linux/bin/code.sh', { base: '.' }) .pipe(replace('@@PRODNAME@@', product.nameLong)) @@ -342,6 +386,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 = [ @@ -365,10 +438,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( @@ -389,6 +468,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' } }, @@ -404,46 +485,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')); @@ -451,24 +509,19 @@ gulp.task(task.define( ) )); -gulp.task('vscode-translations-pull', function () { - return es.merge([...i18n.defaultLanguages, ...i18n.extraLanguages].map(language => { - let 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 () { - let options = minimist(process.argv.slice(2), { + const options = minimist(process.argv.slice(2), { string: 'location', default: { location: '../vscode-translations-import' } }); return es.merge([...i18n.defaultLanguages, ...i18n.extraLanguages].map(language => { - let id = language.id; + const id = language.id; return gulp.src(`${options.location}/${id}/vscode-setup/messages.xlf`) .pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id])) .pipe(vfs.dest(`./build/win32/i18n`)); })); }); + +// #endregion diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 7d0f70f9bef..cdc887013d8 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -12,16 +12,22 @@ const shell = require('gulp-shell'); const es = require('event-stream'); const vfs = require('vinyl-fs'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); 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 commit = 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 +80,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 +186,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 +220,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 f0ad617f405..6de4d03d414 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -9,8 +9,9 @@ const gulp = require('gulp'); const path = require('path'); const es = require('event-stream'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); -const common = require('./lib/optimize'); +const optimize = require('./lib/optimize'); const product = require('../product.json'); const rename = require('gulp-rename'); const filter = require('gulp-filter'); @@ -26,13 +27,13 @@ const REPO_ROOT = path.dirname(__dirname); const BUILD_ROOT = path.dirname(REPO_ROOT); const WEB_FOLDER = path.join(REPO_ROOT, 'remote', 'web'); -const commit = util.getVersion(REPO_ROOT); +const commit = getVersion(REPO_ROOT); const quality = product.quality; const version = (quality && quality !== 'stable') ? `${packageJson.version}-${quality}` : packageJson.version; 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', @@ -70,6 +71,7 @@ const vscodeWebEntryPoints = _.flatten([ buildfile.workerNotebook, buildfile.workerLanguageDetection, buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, buildfile.keyboardMaps, buildfile.workbenchWeb ]); @@ -153,24 +155,28 @@ exports.createVSCodeWebFileContentMapper = createVSCodeWebFileContentMapper; const optimizeVSCodeWebTask = task.define('optimize-vscode-web', task.series( util.rimraf('out-vscode-web'), - common.optimizeTask({ - src: 'out-build', - entryPoints: _.flatten(vscodeWebEntryPoints), - otherSources: [], - resources: vscodeWebResources, - loaderConfig: common.loaderConfig(), - externalLoaderInfo: util.createExternalLoaderConfig(product.webEndpointUrl, commit, quality), - out: 'out-vscode-web', - inlineAmdImages: true, - bundleInfo: undefined, - fileContentMapper: createVSCodeWebFileContentMapper('.build/web/extensions', product) - }) + optimize.optimizeTask( + { + out: 'out-vscode-web', + amd: { + src: 'out-build', + entryPoints: _.flatten(vscodeWebEntryPoints), + otherSources: [], + resources: vscodeWebResources, + loaderConfig: optimize.loaderConfig(), + externalLoaderInfo: util.createExternalLoaderConfig(product.webEndpointUrl, commit, quality), + inlineAmdImages: true, + bundleInfo: undefined, + fileContentMapper: createVSCodeWebFileContentMapper('.build/web/extensions', product) + } + } + ) )); const minifyVSCodeWebTask = task.define('minify-vscode-web', task.series( optimizeVSCodeWebTask, util.rimraf('out-vscode-web-min'), - common.minifyTask('out-vscode-web', `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`) + optimize.minifyTask('out-vscode-web', `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`) )); gulp.task(minifyVSCodeWebTask); @@ -208,7 +214,7 @@ function packageTask(sourceFolderName, destinationFolderName) { gulp.src('resources/server/code-512.png', { base: 'resources/server' }) ); - let all = es.merge( + const all = es.merge( packageJsonStream, license, sources, @@ -218,7 +224,7 @@ function packageTask(sourceFolderName, destinationFolderName) { pwaicons ); - let result = all + const result = all .pipe(util.skipDirectories()) .pipe(util.fixWin32DirectoryPermissions()); @@ -229,7 +235,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/gulpfile.vscode.win32.js b/build/gulpfile.vscode.win32.js index 81ba5095816..9117a021b5a 100644 --- a/build/gulpfile.vscode.win32.js +++ b/build/gulpfile.vscode.win32.js @@ -87,6 +87,7 @@ function buildWin32Setup(arch, target) { productJson['target'] = target; fs.writeFileSync(productJsonPath, JSON.stringify(productJson, undefined, '\t')); + const quality = product.quality; const definitions = { NameLong: product.nameLong, NameShort: product.nameShort, @@ -109,9 +110,19 @@ function buildWin32Setup(arch, target) { RepoDir: repoPath, OutputDir: outputPath, InstallTarget: target, - ProductJsonPath: productJsonPath + ProductJsonPath: productJsonPath, + Quality: quality }; + if (quality === 'insider') { + const appxPackagePrefix = 'code_insiders'; + definitions['AppxPackage'] = `${appxPackagePrefix}_explorer_${arch}.appx`; + if (arch === 'ia32') { + definitions['AppxPackage'] = `${appxPackagePrefix}_explorer_x86.appx`; + } + definitions['AppxPackageFullname'] = `Microsoft.${product.win32RegValueName}_1.0.0.0_neutral__8wekyb3d8bbwe`; + } + packageInnoSetup(issPath, { definitions }, cb); }; } diff --git a/build/hygiene.js b/build/hygiene.js index 1668e508ec9..67f074c4ac0 100644 --- a/build/hygiene.js +++ b/build/hygiene.js @@ -10,6 +10,7 @@ const vfs = require('vinyl-fs'); const path = require('path'); const fs = require('fs'); const pall = require('p-all'); + const { all, copyrightFilter, unicodeFilter, indentationFilter, tsFormattingFilter, eslintFilter } = require('./filters'); const copyrightHeaderLines = [ @@ -116,8 +117,8 @@ function hygiene(some, linting = true) { }) .then( (result) => { - let original = result.src.replace(/\r\n/gm, '\n'); - let formatted = result.dest.replace(/\r\n/gm, '\n'); + const original = result.src.replace(/\r\n/gm, '\n'); + const formatted = result.dest.replace(/\r\n/gm, '\n'); if (original !== formatted) { console.error( @@ -173,8 +174,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')) @@ -292,7 +292,7 @@ if (require.main === module) { .then( (vinyls) => new Promise((c, e) => - hygiene(es.readArray(vinyls)) + hygiene(es.readArray(vinyls).pipe(filter(all))) .on('end', () => c()) .on('error', e) ) diff --git a/build/lib/asar.js b/build/lib/asar.js index 708005791f6..9ee1616fdfa 100644 --- a/build/lib/asar.js +++ b/build/lib/asar.js @@ -1,8 +1,8 @@ +"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.createAsar = void 0; const path = require("path"); @@ -81,7 +81,7 @@ function createAsar(folderPath, unpackGlobs, destFilename) { out.push(file.contents); } }, function () { - let finish = () => { + const finish = () => { { const headerPickle = pickle.createEmpty(); headerPickle.writeString(JSON.stringify(filesystem.header)); diff --git a/build/lib/asar.ts b/build/lib/asar.ts index 18ab7b01946..44a6416bdfb 100644 --- a/build/lib/asar.ts +++ b/build/lib/asar.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as path from 'path'; import * as es from 'event-stream'; const pickle = require('chromium-pickle-js'); @@ -98,7 +96,7 @@ export function createAsar(folderPath: string, unpackGlobs: string[], destFilena } }, function () { - let finish = () => { + const finish = () => { { const headerPickle = pickle.createEmpty(); headerPickle.writeString(JSON.stringify(filesystem.header)); diff --git a/build/lib/builtInExtensions.js b/build/lib/builtInExtensions.js index 2671a5a3a6c..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('âœ”ī¸Ž'))); } @@ -102,7 +116,7 @@ function getBuiltInExtensions() { const control = readControlFile(); const streams = []; for (const extension of [...builtInExtensions, ...webBuiltInExtensions]) { - let controlState = control[extension.name] || 'marketplace'; + const controlState = control[extension.name] || 'marketplace'; control[extension.name] = controlState; streams.push(syncExtension(extension, controlState)); } diff --git a/build/lib/builtInExtensions.ts b/build/lib/builtInExtensions.ts index 1abc85b3b09..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('âœ”ī¸Ž'))); } @@ -143,7 +158,7 @@ export function getBuiltInExtensions(): Promise { const streams: Stream[] = []; for (const extension of [...builtInExtensions, ...webBuiltInExtensions]) { - let controlState = control[extension.name] || 'marketplace'; + const controlState = control[extension.name] || 'marketplace'; control[extension.name] = controlState; streams.push(syncExtension(extension, controlState)); diff --git a/build/lib/bundle.js b/build/lib/bundle.js index 8c1967d4c68..497ac4fb67e 100644 --- a/build/lib/bundle.js +++ b/build/lib/bundle.js @@ -42,14 +42,20 @@ function bundle(entryPoints, config, callback) { if (!config.paths['vs/css']) { config.paths['vs/css'] = 'out-build/vs/css.build'; } + config.buildForceInvokeFactory = config.buildForceInvokeFactory || {}; + config.buildForceInvokeFactory['vs/nls'] = true; + config.buildForceInvokeFactory['vs/css'] = true; loader.config(config); loader(['require'], (localRequire) => { - const resolvePath = (path) => { - const r = localRequire.toUrl(path); - if (!/\.js/.test(r)) { - return r + '.js'; + const resolvePath = (entry) => { + let r = localRequire.toUrl(entry.path); + if (!r.endsWith('.js')) { + r += '.js'; } - return r; + // avoid packaging the build version of plugins: + r = r.replace('vs/nls.build.js', 'vs/nls.js'); + r = r.replace('vs/css.build.js', 'vs/css.js'); + return { path: r, amdModuleId: entry.amdModuleId }; }; for (const moduleId in entryPointsMap) { const entryPoint = entryPointsMap[moduleId]; @@ -298,9 +304,18 @@ function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend, if (module.shim) { mainResult.sources.push(emitShimmedModule(c, deps[c], module.shim, module.path, contents)); } - else { + else if (module.defineLocation) { mainResult.sources.push(emitNamedModule(c, module.defineLocation, module.path, contents)); } + else { + const moduleCopy = { + id: module.id, + path: module.path, + defineLocation: module.defineLocation, + dependencies: module.dependencies + }; + throw new Error(`Cannot bundle module '${module.id}' for entry point '${entryPoint}' because it has no shim and it lacks a defineLocation: ${JSON.stringify(moduleCopy)}`); + } }); Object.keys(usedPlugins).forEach((pluginName) => { const plugin = usedPlugins[pluginName]; @@ -321,10 +336,13 @@ function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend, plugin.writeFile(pluginName, entryPoint, req, write, {}); } }); - const toIFile = (path) => { - const contents = readFileAndRemoveBOM(path); + const toIFile = (entry) => { + let contents = readFileAndRemoveBOM(entry.path); + if (entry.amdModuleId) { + contents = contents.replace(/^define\(/m, `define("${entry.amdModuleId}",`); + } return { - path: path, + path: entry.path, contents: contents }; }; diff --git a/build/lib/bundle.ts b/build/lib/bundle.ts index a1130d4bbbd..c5fdc2da18c 100644 --- a/build/lib/bundle.ts +++ b/build/lib/bundle.ts @@ -15,7 +15,7 @@ interface IPosition { interface IBuildModuleInfo { id: string; path: string; - defineLocation: IPosition; + defineLocation: IPosition | null; dependencies: string[]; shim: string; exports: any; @@ -42,12 +42,17 @@ interface ILoaderPluginReqFunc { toUrl(something: string): string; } +export interface IExtraFile { + path: string; + amdModuleId?: string; +} + export interface IEntryPoint { name: string; include?: string[]; exclude?: string[]; - prepend?: string[]; - append?: string[]; + prepend?: IExtraFile[]; + append?: IExtraFile[]; dest?: string; } @@ -92,6 +97,13 @@ interface IPartialBundleResult { export interface ILoaderConfig { isBuild?: boolean; paths?: { [path: string]: any }; + /* + * Normally, during a build, no module factories are invoked. This can be used + * to forcefully execute a module's factory. + */ + buildForceInvokeFactory: { + [moduleId: string]: boolean; + }; } /** @@ -132,15 +144,21 @@ export function bundle(entryPoints: IEntryPoint[], config: ILoaderConfig, callba if (!config.paths['vs/css']) { config.paths['vs/css'] = 'out-build/vs/css.build'; } + config.buildForceInvokeFactory = config.buildForceInvokeFactory || {}; + config.buildForceInvokeFactory['vs/nls'] = true; + config.buildForceInvokeFactory['vs/css'] = true; loader.config(config); loader(['require'], (localRequire: any) => { - const resolvePath = (path: string) => { - const r = localRequire.toUrl(path); - if (!/\.js/.test(r)) { - return r + '.js'; + const resolvePath = (entry: IExtraFile) => { + let r = localRequire.toUrl(entry.path); + if (!r.endsWith('.js')) { + r += '.js'; } - return r; + // avoid packaging the build version of plugins: + r = r.replace('vs/nls.build.js', 'vs/nls.js'); + r = r.replace('vs/css.build.js', 'vs/css.js'); + return { path: r, amdModuleId: entry.amdModuleId }; }; for (const moduleId in entryPointsMap) { const entryPoint = entryPointsMap[moduleId]; @@ -403,8 +421,8 @@ function emitEntryPoint( deps: IGraph, entryPoint: string, includedModules: string[], - prepend: string[], - append: string[], + prepend: IExtraFile[], + append: IExtraFile[], dest: string | undefined ): IEmitEntryPointResult { if (!dest) { @@ -444,8 +462,16 @@ function emitEntryPoint( if (module.shim) { mainResult.sources.push(emitShimmedModule(c, deps[c], module.shim, module.path, contents)); - } else { + } else if (module.defineLocation) { mainResult.sources.push(emitNamedModule(c, module.defineLocation, module.path, contents)); + } else { + const moduleCopy = { + id: module.id, + path: module.path, + defineLocation: module.defineLocation, + dependencies: module.dependencies + }; + throw new Error(`Cannot bundle module '${module.id}' for entry point '${entryPoint}' because it has no shim and it lacks a defineLocation: ${JSON.stringify(moduleCopy)}`); } }); @@ -470,10 +496,13 @@ function emitEntryPoint( } }); - const toIFile = (path: string): IFile => { - const contents = readFileAndRemoveBOM(path); + const toIFile = (entry: IExtraFile): IFile => { + let contents = readFileAndRemoveBOM(entry.path); + if (entry.amdModuleId) { + contents = contents.replace(/^define\(/m, `define("${entry.amdModuleId}",`); + } return { - path: path, + path: entry.path, contents: contents }; }; diff --git a/build/lib/compilation.js b/build/lib/compilation.js index db489e01f9d..f5d46d7b20c 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -1,10 +1,10 @@ +"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.watchApiProposalNamesTask = exports.compileApiProposalNamesTask = exports.watchTask = exports.compileTask = void 0; +exports.watchApiProposalNamesTask = exports.compileApiProposalNamesTask = exports.watchTask = exports.compileTask = exports.transpileTask = void 0; const es = require("event-stream"); const fs = require("fs"); const gulp = require("gulp"); @@ -19,10 +19,11 @@ 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}`); - let options = {}; + const options = {}; options.verbose = false; options.sourceMap = true; if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry @@ -34,7 +35,7 @@ function getTypeScriptCompilerOptions(src) { options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 0 : 1; return options; } -function createCompile(src, build, emitError) { +function createCompile(src, build, emitError, transpileOnly) { const tsb = require('./tsb'); const sourcemaps = require('gulp-sourcemaps'); const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json'); @@ -42,7 +43,11 @@ function createCompile(src, build, emitError) { if (!build) { overrideOptions.inlineSourceMap = true; } - const compilation = tsb.create(projectPath, overrideOptions, false, 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)); @@ -59,7 +64,7 @@ function createCompile(src, build, emitError) { .pipe(noDeclarationsFilter) .pipe(build ? nls.nls() : es.through()) .pipe(noDeclarationsFilter.restore) - .pipe(sourcemaps.write('.', { + .pipe(transpileOnly ? es.through() : sourcemaps.write('.', { addComment: false, includeContent: !!build, sourceRoot: overrideOptions.sourceRoot @@ -73,14 +78,24 @@ function createCompile(src, build, emitError) { }; return pipeline; } +function transpileTask(src, out, swc) { + return function () { + const transpile = createCompile(src, false, true, { swc }); + const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); + return srcPipe + .pipe(transpile()) + .pipe(gulp.dest(out)); + }; +} +exports.transpileTask = transpileTask; function compileTask(src, out, build) { return function () { if (os.totalmem() < 4000000000) { throw new Error('compilation requires 4GB of RAM'); } - const compile = createCompile(src, build, true); + const compile = createCompile(src, build, true, false); const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); - let generator = new MonacoGenerator(false); + const generator = new MonacoGenerator(false); if (src === 'src') { generator.execute(); } @@ -93,10 +108,10 @@ function compileTask(src, out, build) { exports.compileTask = compileTask; function watchTask(out, build) { return function () { - const compile = createCompile('src', build); + const compile = createCompile('src', build, false, false); const src = gulp.src('src/**', { base: 'src' }); const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); - let generator = new MonacoGenerator(true); + const generator = new MonacoGenerator(true); generator.execute(); return watchSrc .pipe(generator.stream) @@ -112,7 +127,7 @@ class MonacoGenerator { this._isWatch = isWatch; this.stream = es.through(); this._watchedFiles = {}; - let onWillReadFile = (moduleId, filePath) => { + const onWillReadFile = (moduleId, filePath) => { if (!this._isWatch) { return; } @@ -149,7 +164,7 @@ class MonacoGenerator { }, 20); } _run() { - let r = monacodts.run3(this._declarationResolver); + const r = monacodts.run3(this._declarationResolver); if (!r && !this._isWatch) { // The build must always be able to generate the monaco.d.ts throw new Error(`monaco.d.ts generation error - Cannot continue`); @@ -178,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(); @@ -200,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 d40b6139cc0..b9769822d73 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as es from 'event-stream'; import * as fs from 'fs'; import * as gulp from 'gulp'; @@ -19,14 +17,16 @@ 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 { const rootDir = path.join(__dirname, `../../${src}`); - let options: ts.CompilerOptions = {}; + const options: ts.CompilerOptions = {}; options.verbose = false; options.sourceMap = true; if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry @@ -39,7 +39,7 @@ function getTypeScriptCompilerOptions(src: string): ts.CompilerOptions { return options; } -function createCompile(src: string, build: boolean, emitError?: 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'); @@ -50,7 +50,11 @@ function createCompile(src: string, build: boolean, emitError?: boolean) { overrideOptions.inlineSourceMap = true; } - const compilation = tsb.create(projectPath, overrideOptions, false, 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'); @@ -70,7 +74,7 @@ function createCompile(src: string, build: boolean, emitError?: boolean) { .pipe(noDeclarationsFilter) .pipe(build ? nls.nls() : es.through()) .pipe(noDeclarationsFilter.restore) - .pipe(sourcemaps.write('.', { + .pipe(transpileOnly ? es.through() : sourcemaps.write('.', { addComment: false, includeContent: !!build, sourceRoot: overrideOptions.sourceRoot @@ -86,6 +90,19 @@ function createCompile(src: string, build: boolean, emitError?: boolean) { return pipeline; } +export function transpileTask(src: string, out: string, swc: boolean): () => NodeJS.ReadWriteStream { + + return function () { + + const transpile = createCompile(src, false, true, { swc }); + const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); + + return srcPipe + .pipe(transpile()) + .pipe(gulp.dest(out)); + }; +} + export function compileTask(src: string, out: string, build: boolean): () => NodeJS.ReadWriteStream { return function () { @@ -94,9 +111,9 @@ export function compileTask(src: string, out: string, build: boolean): () => Nod throw new Error('compilation requires 4GB of RAM'); } - const compile = createCompile(src, build, true); + const compile = createCompile(src, build, true, false); const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); - let generator = new MonacoGenerator(false); + const generator = new MonacoGenerator(false); if (src === 'src') { generator.execute(); } @@ -111,12 +128,12 @@ export function compileTask(src: string, out: string, build: boolean): () => Nod export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteStream { return function () { - const compile = createCompile('src', build); + const compile = createCompile('src', build, false, false); const src = gulp.src('src/**', { base: 'src' }); const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); - let generator = new MonacoGenerator(true); + const generator = new MonacoGenerator(true); generator.execute(); return watchSrc @@ -140,7 +157,7 @@ class MonacoGenerator { this._isWatch = isWatch; this.stream = es.through(); this._watchedFiles = {}; - let onWillReadFile = (moduleId: string, filePath: string) => { + const onWillReadFile = (moduleId: string, filePath: string) => { if (!this._isWatch) { return; } @@ -182,7 +199,7 @@ class MonacoGenerator { } private _run(): monacodts.IMonacoDeclarationResult | null { - let r = monacodts.run3(this._declarationResolver); + const r = monacodts.run3(this._declarationResolver); if (!r && !this._isWatch) { // The build must always be able to generate the monaco.d.ts throw new Error(`monaco.d.ts generation error - Cannot continue`); @@ -215,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(); @@ -239,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/dependencies.js b/build/lib/dependencies.js index cbc6cec9d81..3b5a9e3e098 100644 --- a/build/lib/dependencies.js +++ b/build/lib/dependencies.js @@ -1,8 +1,8 @@ +"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.getProductionDependencies = void 0; const path = require("path"); diff --git a/build/lib/dependencies.ts b/build/lib/dependencies.ts index 516da11be67..eb195154924 100644 --- a/build/lib/dependencies.ts +++ b/build/lib/dependencies.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as path from 'path'; import * as cp from 'child_process'; import * as _ from 'underscore'; diff --git a/build/lib/electron.js b/build/lib/electron.js index 362f6c38e69..38f13d0ff08 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -1,8 +1,8 @@ +"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.config = void 0; const fs = require("fs"); @@ -11,12 +11,13 @@ const vfs = require("vinyl-fs"); const filter = require("gulp-filter"); const _ = require("underscore"); const util = require("./util"); +const getVersion_1 = require("./getVersion"); function isDocumentSuffix(str) { return str === 'document' || str === 'script' || str === 'file' || str === 'source code'; } const root = path.dirname(path.dirname(__dirname)); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); -const commit = util.getVersion(root); +const commit = (0, getVersion_1.getVersion)(root); const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); /** * Generate a `DarwinDocumentType` given a list of file extensions, an icon name, and an optional suffix or file type name. @@ -152,6 +153,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 ed91f8c2f71..247de01c563 100644 --- a/build/lib/electron.ts +++ b/build/lib/electron.ts @@ -3,14 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as fs from 'fs'; import * as path from 'path'; import * as vfs from 'vinyl-fs'; import * as filter from 'gulp-filter'; import * as _ from 'underscore'; import * as util from './util'; +import { getVersion } from './getVersion'; type DarwinDocumentSuffix = 'document' | 'script' | 'file' | 'source code'; type DarwinDocumentType = { @@ -28,7 +27,7 @@ function isDocumentSuffix(str?: string): str is DarwinDocumentSuffix { const root = path.dirname(path.dirname(__dirname)); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); -const commit = util.getVersion(root); +const commit = getVersion(root); const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); @@ -169,6 +168,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 7c9c624a407..00000000000 --- a/build/lib/eslint/code-no-look-behind-regex.js +++ /dev/null @@ -1,42 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; -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 b603f4d8e09..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 (let 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 (let 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 530464f37b5..00000000000 --- a/build/lib/eslint/code-no-unused-expressions.js +++ /dev/null @@ -1,125 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -// FORKED FROM https://github.com/eslint/eslint/blob/b23ad0d789a909baf8d7c41a35bc53df932eaf30/lib/rules/no-unused-expressions.js -// and added support for `OptionalCallExpression`, see https://github.com/facebook/create-react-app/issues/8107 and https://github.com/eslint/eslint/issues/12642 -/** - * @fileoverview Flag expressions in statement position that do not side effect - * @author Michael Ficarra - */ -'use strict'; -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 d016f0d2ebc..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 (let 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 50fc4dd945b..f69b3322018 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -25,9 +25,10 @@ const buffer = require('gulp-buffer'); const jsoncParser = require("jsonc-parser"); const dependencies_1 = require("./dependencies"); const _ = require("underscore"); -const util = require('./util'); +const builtInExtensions_1 = require("./builtInExtensions"); +const getVersion_1 = require("./getVersion"); const root = path.dirname(path.dirname(__dirname)); -const commit = util.getVersion(root); +const commit = (0, getVersion_1.getVersion)(root); const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; function minifyExtensionResources(input) { const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true }); @@ -245,8 +246,6 @@ const excludedExtensions = [ 'vscode-test-resolver', 'ms-vscode.node-debug', 'ms-vscode.node-debug2', - 'vscode-notebook-tests', - 'vscode-custom-editor-tests', ]; const marketplaceWebExtensionsExclude = new Set([ 'ms-vscode.node-debug', @@ -313,16 +312,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; @@ -345,19 +343,27 @@ function scanBuiltinExtensions(extensionsRoot, exclude = []) { if (!fs.existsSync(packageJSONPath)) { continue; } - let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); + const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); if (!isWebExtension(packageJSON)) { continue; } 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, }); @@ -373,7 +379,7 @@ function translatePackageJSON(packageJSON, packageNLSPath) { const CharCode_PC = '%'.charCodeAt(0); const packageNls = JSON.parse(fs.readFileSync(packageNLSPath).toString()); const translate = (obj) => { - for (let key in obj) { + for (const key in obj) { const val = obj[key]; if (Array.isArray(val)) { val.forEach(translate); @@ -400,6 +406,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 312b830b903..36f29fcf3a1 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -25,9 +25,11 @@ import * as jsoncParser from 'jsonc-parser'; import webpack = require('webpack'); import { getProductionDependencies } from './dependencies'; import _ = require('underscore'); -const util = require('./util'); +import { getExtensionStream } from './builtInExtensions'; +import { getVersion } from './getVersion'; + const root = path.dirname(path.dirname(__dirname)); -const commit = util.getVersion(root); +const commit = getVersion(root); const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; function minifyExtensionResources(input: Stream): Stream { @@ -285,8 +287,6 @@ const excludedExtensions = [ 'vscode-test-resolver', 'ms-vscode.node-debug', 'ms-vscode.node-debug2', - 'vscode-notebook-tests', - 'vscode-custom-editor-tests', ]; const marketplaceWebExtensionsExclude = new Set([ @@ -382,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 : []) @@ -391,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; @@ -413,6 +412,7 @@ export interface IScannedBuiltinExtension { extensionPath: string; packageJSON: any; packageNLS?: any; + browserNlsMetadataPath?: string; readmePath?: string; changelogPath?: string; } @@ -430,13 +430,20 @@ export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] if (!fs.existsSync(packageJSONPath)) { continue; } - let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); + const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); if (!isWebExtension(packageJSON)) { continue; } 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]; @@ -444,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, }); @@ -461,7 +469,7 @@ export function translatePackageJSON(packageJSON: string, packageNLSPath: string const CharCode_PC = '%'.charCodeAt(0); const packageNls: NLSFormat = JSON.parse(fs.readFileSync(packageNLSPath).toString()); const translate = (obj: any) => { - for (let key in obj) { + for (const key in obj) { const val = obj[key]; if (Array.isArray(val)) { val.forEach(translate); @@ -487,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', ]; @@ -500,7 +509,7 @@ export async function webpackExtensions(taskName: string, isWatch: boolean, webp function addConfig(configOrFn: webpack.Configuration | Function) { let config; if (typeof configOrFn === 'function') { - config = configOrFn({}, {}); + config = (configOrFn as Function)({}, {}); webpackConfigs.push(config); } else { config = configOrFn; diff --git a/build/lib/getVersion.js b/build/lib/getVersion.js new file mode 100644 index 00000000000..3f51e62f80d --- /dev/null +++ b/build/lib/getVersion.js @@ -0,0 +1,16 @@ +"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.getVersion = void 0; +const git = require("./git"); +function getVersion(root) { + let version = process.env['VSCODE_DISTRO_COMMIT'] || process.env['BUILD_SOURCEVERSION']; + if (!version || !/^[0-9a-f]{40}$/i.test(version.trim())) { + version = git.getVersion(root); + } + return version; +} +exports.getVersion = getVersion; diff --git a/build/lib/getVersion.ts b/build/lib/getVersion.ts new file mode 100644 index 00000000000..461302962d2 --- /dev/null +++ b/build/lib/getVersion.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as git from './git'; + +export function getVersion(root: string): string | undefined { + let version = process.env['VSCODE_DISTRO_COMMIT'] || process.env['BUILD_SOURCEVERSION']; + + if (!version || !/^[0-9a-f]{40}$/i.test(version.trim())) { + version = git.getVersion(root); + } + + return version; +} diff --git a/build/lib/git.js b/build/lib/git.js index 1726f76fcc7..0aa340347ac 100644 --- a/build/lib/git.js +++ b/build/lib/git.js @@ -1,10 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getVersion = void 0; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getVersion = void 0; const path = require("path"); const fs = require("fs"); /** @@ -45,7 +45,7 @@ function getVersion(repo) { } const refsRegex = /^([0-9a-f]{40})\s+(.+)$/gm; let refsMatch; - let refs = {}; + const refs = {}; while (refsMatch = refsRegex.exec(refsRaw)) { refs[refsMatch[2]] = refsMatch[1]; } diff --git a/build/lib/git.ts b/build/lib/git.ts index dc9c667c21b..dbb424f21df 100644 --- a/build/lib/git.ts +++ b/build/lib/git.ts @@ -2,8 +2,6 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as path from 'path'; import * as fs from 'fs'; @@ -51,7 +49,7 @@ export function getVersion(repo: string): string | undefined { const refsRegex = /^([0-9a-f]{40})\s+(.+)$/gm; let refsMatch: RegExpExecArray | null; - let refs: { [ref: string]: string } = {}; + const refs: { [ref: string]: string } = {}; while (refsMatch = refsRegex.exec(refsRaw)) { refs[refsMatch[2]] = refsMatch[1]; diff --git a/build/lib/i18n.js b/build/lib/i18n.js index e89cdf1504e..24e622bc7a8 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -4,19 +4,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.prepareI18nFiles = exports.pullSetupXlfFiles = exports.findObsoleteResources = exports.pushXlfFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.Limiter = exports.XLF = exports.Line = exports.externalExtensionsWithTranslations = exports.extraLanguages = exports.defaultLanguages = void 0; +exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.XLF = exports.Line = exports.extraLanguages = exports.defaultLanguages = void 0; const path = require("path"); const fs = require("fs"); const event_stream_1 = require("event-stream"); const File = require("vinyl"); const Is = require("is"); const xml2js = require("xml2js"); -const https = require("https"); const gulp = require("gulp"); const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); const iconv = require("@vscode/iconv-lite-umd"); -const NUMBER_OF_CONCURRENT_DOWNLOADS = 4; +const l10n_dev_1 = require("@vscode/l10n-dev"); function log(message, ...rest) { fancyLog(ansiColors.green('[i18n]'), message, ...rest); } @@ -38,7 +37,7 @@ exports.extraLanguages = [ { id: 'tr', folderName: 'trk' } ]; // non built-in extensions also that are transifex and need to be part of the language packs -exports.externalExtensionsWithTranslations = { +const externalExtensionsWithTranslations = { 'vscode-chrome-debug': 'msjsdiag.debugger-for-chrome', 'vscode-node-debug': 'ms-vscode.node-debug', 'vscode-node-debug2': 'ms-vscode.node-debug2' @@ -46,7 +45,7 @@ exports.externalExtensionsWithTranslations = { var LocalizeInfo; (function (LocalizeInfo) { function is(value) { - let candidate = value; + const candidate = value; return Is.defined(candidate) && Is.string(candidate.key) && (Is.undef(candidate.comment) || (Is.array(candidate.comment) && candidate.comment.every(element => Is.string(element)))); } LocalizeInfo.is = is; @@ -57,25 +56,12 @@ var BundledFormat; if (Is.undef(value)) { return false; } - let candidate = value; - let length = Object.keys(value).length; + const candidate = value; + const length = Object.keys(value).length; return length === 3 && Is.defined(candidate.keys) && Is.defined(candidate.messages) && Is.defined(candidate.bundles); } BundledFormat.is = is; })(BundledFormat || (BundledFormat = {})); -var PackageJsonFormat; -(function (PackageJsonFormat) { - function is(value) { - if (Is.undef(value) || !Is.object(value)) { - return false; - } - return Object.keys(value).every(key => { - let element = value[key]; - return Is.string(element) || (Is.object(element) && Is.defined(element.message) && Is.defined(element.comment)); - }); - } - PackageJsonFormat.is = is; -})(PackageJsonFormat || (PackageJsonFormat = {})); class Line { constructor(indent = 0) { this.buffer = []; @@ -133,9 +119,9 @@ class XLF { } this.numberOfMessages += keys.length; this.files[original] = []; - let existingKeys = new Set(); + const existingKeys = new Set(); for (let i = 0; i < keys.length; i++) { - let key = keys[i]; + const key = keys[i]; let realKey; let comment; if (Is.string(key)) { @@ -152,7 +138,7 @@ class XLF { continue; } existingKeys.add(realKey); - let message = encodeEntities(messages[i]); + const message = encodeEntities(messages[i]); this.files[original].push({ id: realKey, message: message, comment: comment }); } } @@ -178,41 +164,16 @@ class XLF { this.appendNewLine('', 0); } appendNewLine(content, indent) { - let line = new Line(indent); + const line = new Line(indent); line.append(content); this.buffer.push(line.toString()); } } exports.XLF = XLF; -XLF.parsePseudo = function (xlfString) { - return new Promise((resolve) => { - let parser = new xml2js.Parser(); - let files = []; - parser.parseString(xlfString, function (_err, result) { - const fileNodes = result['xliff']['file']; - fileNodes.forEach(file => { - const originalFilePath = file.$.original; - const messages = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit) => { - const key = unit.$.id; - const val = pseudify(unit.source[0]['_'].toString()); - if (key && val) { - messages[key] = decodeEntities(val); - } - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); - } - }); - resolve(files); - }); - }); -}; XLF.parse = function (xlfString) { return new Promise((resolve, reject) => { - let parser = new xml2js.Parser(); - let files = []; + const parser = new xml2js.Parser(); + const files = []; parser.parseString(xlfString, function (err, result) { if (err) { reject(new Error(`XLF parsing error: Failed to parse XLIFF string. ${err}`)); @@ -222,11 +183,11 @@ XLF.parse = function (xlfString) { reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); } fileNodes.forEach((file) => { - const originalFilePath = file.$.original; - if (!originalFilePath) { + const name = file.$.original; + if (!name) { reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); } - let language = file.$['target-language']; + const language = file.$['target-language']; if (!language) { reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); } @@ -244,45 +205,18 @@ XLF.parse = function (xlfString) { val = val._ ? val._ : ''; } if (!key) { - reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${originalFilePath} is missing the ID attribute.`)); + reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${name} is missing the ID attribute.`)); return; } messages[key] = decodeEntities(val); }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); + files.push({ messages, name, language: language.toLowerCase() }); } }); resolve(files); }); }); }; -class Limiter { - constructor(maxDegreeOfParalellism) { - this.maxDegreeOfParalellism = maxDegreeOfParalellism; - this.outstandingPromises = []; - this.runningPromises = 0; - } - queue(factory) { - return new Promise((c, e) => { - this.outstandingPromises.push({ factory, c, e }); - this.consume(); - }); - } - consume() { - while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { - const iLimitedTask = this.outstandingPromises.shift(); - this.runningPromises++; - const promise = iLimitedTask.factory(); - promise.then(iLimitedTask.c).catch(iLimitedTask.e); - promise.then(() => this.consumed()).catch(() => this.consumed()); - } - } - consumed() { - this.runningPromises--; - this.consume(); - } -} -exports.Limiter = Limiter; function sortLanguages(languages) { return languages.sort((a, b) => { return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); @@ -295,9 +229,10 @@ function stripComments(content) { // Second group matches a single quoted string // Third group matches a multi line comment // Forth group matches a single line comment - const regexp = /("[^"\\]*(?:\\.[^"\\]*)*")|('[^'\\]*(?:\\.[^'\\]*)*')|(\/\*[^\/\*]*(?:(?:\*|\/)[^\/\*]*)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; - let result = content.replace(regexp, (match, _m1, _m2, m3, m4) => { - // Only one of m1, m2, m3, m4 matches + // Fifth group matches a trailing comma + const regexp = /("[^"\\]*(?:\\.[^"\\]*)*")|('[^'\\]*(?:\\.[^'\\]*)*')|(\/\*[^\/\*]*(?:(?:\*|\/)[^\/\*]*)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))|(,\s*[}\]])/g; + const result = content.replace(regexp, (match, _m1, _m2, m3, m4, m5) => { + // Only one of m1, m2, m3, m4, m5 matches if (m3) { // A block comment. Replace with nothing return ''; @@ -313,6 +248,10 @@ function stripComments(content) { return ''; } } + else if (m5) { + // Remove the trailing comma + return match.substring(1); + } else { // We match a string return match; @@ -356,20 +295,20 @@ function escapeCharacters(value) { return result.join(''); } function processCoreBundleFormat(fileHeader, languages, json, emitter) { - let keysSection = json.keys; - let messageSection = json.messages; - let bundleSection = json.bundles; - let statistics = Object.create(null); - let defaultMessages = Object.create(null); - let modules = Object.keys(keysSection); + const keysSection = json.keys; + const messageSection = json.messages; + const bundleSection = json.bundles; + const statistics = Object.create(null); + const defaultMessages = Object.create(null); + const modules = Object.keys(keysSection); modules.forEach((module) => { - let keys = keysSection[module]; - let messages = messageSection[module]; + const keys = keysSection[module]; + const messages = messageSection[module]; if (!messages || keys.length !== messages.length) { emitter.emit('error', `Message for module ${module} corrupted. Mismatch in number of keys and messages.`); return; } - let messageMap = Object.create(null); + const messageMap = Object.create(null); defaultMessages[module] = messageMap; keys.map((key, i) => { if (typeof key === 'string') { @@ -380,27 +319,27 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { } }); }); - let languageDirectory = path.join(__dirname, '..', '..', '..', 'vscode-loc', 'i18n'); + const languageDirectory = path.join(__dirname, '..', '..', '..', 'vscode-loc', 'i18n'); if (!fs.existsSync(languageDirectory)) { log(`No VS Code localization repository found. Looking at ${languageDirectory}`); log(`To bundle translations please check out the vscode-loc repository as a sibling of the vscode repository.`); } - let sortedLanguages = sortLanguages(languages); + const sortedLanguages = sortLanguages(languages); sortedLanguages.forEach((language) => { if (process.env['VSCODE_BUILD_VERBOSE']) { log(`Generating nls bundles for: ${language.id}`); } statistics[language.id] = 0; - let localizedModules = Object.create(null); - let languageFolderName = language.translationId || language.id; - let i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); + const localizedModules = Object.create(null); + const languageFolderName = language.translationId || language.id; + const i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); let allMessages; if (fs.existsSync(i18nFile)) { - let content = stripComments(fs.readFileSync(i18nFile, 'utf8')); + const content = stripComments(fs.readFileSync(i18nFile, 'utf8')); allMessages = JSON.parse(content); } modules.forEach((module) => { - let order = keysSection[module]; + const order = keysSection[module]; let moduleMessage; if (allMessages) { moduleMessage = allMessages.contents[module]; @@ -412,7 +351,7 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { moduleMessage = defaultMessages[module]; statistics[language.id] = statistics[language.id] + Object.keys(moduleMessage).length; } - let localizedMessages = []; + const localizedMessages = []; order.forEach((keyInfo) => { let key = null; if (typeof keyInfo === 'string') { @@ -434,14 +373,14 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { localizedModules[module] = localizedMessages; }); Object.keys(bundleSection).forEach((bundle) => { - let modules = bundleSection[bundle]; - let contents = [ + const modules = bundleSection[bundle]; + const contents = [ fileHeader, `define("${bundle}.nls.${language.id}", {` ]; modules.forEach((module, index) => { contents.push(`\t"${module}": [`); - let messages = localizedModules[module]; + const messages = localizedModules[module]; if (!messages) { emitter.emit('error', `Didn't find messages for module ${module}.`); return; @@ -456,11 +395,11 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { }); }); Object.keys(statistics).forEach(key => { - let value = statistics[key]; + const value = statistics[key]; log(`${key} has ${value} untranslated strings.`); }); sortedLanguages.forEach(language => { - let stats = statistics[language.id]; + const stats = statistics[language.id]; if (Is.undef(stats)) { log(`\tNo translations found for language ${language.id}. Using default language instead.`); } @@ -468,7 +407,7 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { } function processNlsFiles(opts) { return (0, event_stream_1.through)(function (file) { - let fileName = path.basename(file.path); + const fileName = path.basename(file.path); if (fileName === 'nls.metadata.json') { let json = null; if (file.isBuffer()) { @@ -486,7 +425,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)) { @@ -504,6 +443,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 }; @@ -525,7 +467,7 @@ function createXlfFilesForCoreBundle() { if (file.isBuffer()) { const xlfs = Object.create(null); const json = JSON.parse(file.contents.toString('utf8')); - for (let coreModule in json.keys) { + for (const coreModule in json.keys) { const projectResource = getResource(coreModule); const resource = projectResource.name; const project = projectResource.project; @@ -544,7 +486,7 @@ function createXlfFilesForCoreBundle() { xlf.addFile(`src/${coreModule}`, keys, messages); } } - for (let resource in xlfs) { + for (const resource in xlfs) { const xlf = xlfs[resource]; const filePath = `${xlf.project}/${resource.replace(/\//g, '_')}.xlf`; const xlfFile = new File({ @@ -566,6 +508,28 @@ function createXlfFilesForCoreBundle() { }); } exports.createXlfFilesForCoreBundle = createXlfFilesForCoreBundle; +function createL10nBundleForExtension(extensionName) { + const result = (0, event_stream_1.through)(); + gulp.src([ + `extensions/${extensionName}/src/**/*.ts`, + ]).pipe((0, event_stream_1.writeArray)((err, files) => { + if (err) { + result.emit('error', err); + return; + } + const json = (0, l10n_dev_1.getL10nJson)(files.map(file => { + return file.contents.toString('utf8'); + })); + if (Object.keys(json).length > 0) { + result.emit('data', new File({ + path: `${extensionName}/bundle.l10n.json`, + contents: Buffer.from(JSON.stringify(json), 'utf8') + })); + } + result.emit('end'); + })); + return result; +} function createXlfFilesForExtensions() { let counter = 0; let folderStreamEnded = false; @@ -576,57 +540,56 @@ function createXlfFilesForExtensions() { if (!stat.isDirectory()) { return; } - let extensionName = path.basename(extensionFolder.path); + const extensionName = path.basename(extensionFolder.path); if (extensionName === 'node_modules') { return; } counter++; - let _xlf; - function getXlf() { - if (!_xlf) { - _xlf = new XLF(extensionsProject); + let _l10nMap; + function getL10nMap() { + if (!_l10nMap) { + _l10nMap = new Map(); } - return _xlf; + return _l10nMap; } - gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe((0, event_stream_1.through)(function (file) { + (0, event_stream_1.merge)(gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }), createL10nBundleForExtension(extensionName)).pipe((0, event_stream_1.through)(function (file) { if (file.isBuffer()) { const buffer = file.contents; const basename = path.basename(file.path); if (basename === 'package.nls.json') { const json = JSON.parse(buffer.toString('utf8')); - const keys = Object.keys(json); - const messages = keys.map((key) => { - const value = json[key]; - if (Is.string(value)) { - return value; - } - else if (value) { - return value.message; - } - else { - return `Unknown message for key: ${key}`; - } - }); - getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); + getL10nMap().set(`extensions/${extensionName}/package`, json); } else if (basename === 'nls.metadata.json') { const json = JSON.parse(buffer.toString('utf8')); const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); - for (let file in json) { + for (const file in json) { const fileContent = json[file]; - getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); + const info = Object.create(null); + for (let i = 0; i < fileContent.messages.length; i++) { + const message = fileContent.messages[i]; + const { key, comment } = LocalizeInfo.is(fileContent.keys[i]) + ? fileContent.keys[i] + : { key: fileContent.keys[i], comment: undefined }; + info[key] = comment ? { message, comment } : message; + } + getL10nMap().set(`extensions/${extensionName}/${relPath}/${file}`, info); } } + else if (basename === 'bundle.l10n.json') { + const json = JSON.parse(buffer.toString('utf8')); + getL10nMap().set(`extensions/${extensionName}/bundle`, json); + } else { this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); return; } } }, function () { - if (_xlf) { - let xlfFile = new File({ + if (_l10nMap?.size > 0) { + const xlfFile = new File({ path: path.join(extensionsProject, extensionName + '.xlf'), - contents: Buffer.from(_xlf.toString(), 'utf8') + contents: Buffer.from((0, l10n_dev_1.getL10nXlf)(_l10nMap), 'utf8') }); folderStream.queue(xlfFile); } @@ -656,14 +619,14 @@ function createXlfFilesForIsl() { else { throw new Error(`Unknown input file ${file.path}`); } - let xlf = new XLF(projectName), keys = [], messages = []; - let model = new TextModel(file.contents.toString()); + const xlf = new XLF(projectName), keys = [], messages = []; + const model = new TextModel(file.contents.toString()); let inMessageSection = false; model.lines.forEach(line => { if (line.length === 0) { return; } - let firstChar = line.charAt(0); + const firstChar = line.charAt(0); switch (firstChar) { case ';': // Comment line; @@ -675,13 +638,13 @@ function createXlfFilesForIsl() { if (!inMessageSection) { return; } - let sections = line.split('='); + const sections = line.split('='); if (sections.length !== 2) { throw new Error(`Badly formatted message found: ${line}`); } else { - let key = sections[0]; - let value = sections[1]; + const key = sections[0]; + const value = sections[1]; if (key.length > 0 && value.length > 0) { keys.push(key); messages.push(value); @@ -697,300 +660,8 @@ function createXlfFilesForIsl() { }); } exports.createXlfFilesForIsl = createXlfFilesForIsl; -function pushXlfFiles(apiHostname, username, password) { - let tryGetPromises = []; - let updateCreatePromises = []; - return (0, event_stream_1.through)(function (file) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - const credentials = `${username}:${password}`; - // Check if resource already exists, if not, then create it. - let promise = tryGetResource(project, slug, apiHostname, credentials); - tryGetPromises.push(promise); - promise.then(exists => { - if (exists) { - promise = updateResource(project, slug, file, apiHostname, credentials); - } - else { - promise = createResource(project, slug, file, apiHostname, credentials); - } - updateCreatePromises.push(promise); - }); - }, function () { - // End the pipe only after all the communication with Transifex API happened - Promise.all(tryGetPromises).then(() => { - Promise.all(updateCreatePromises).then(() => { - this.queue(null); - }).catch((reason) => { throw new Error(reason); }); - }).catch((reason) => { throw new Error(reason); }); - }); -} -exports.pushXlfFiles = pushXlfFiles; -function getAllResources(project, apiHostname, username, password) { - return new Promise((resolve, reject) => { - const credentials = `${username}:${password}`; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - auth: credentials, - method: 'GET' - }; - const request = https.request(options, (res) => { - let buffer = []; - res.on('data', (chunk) => buffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - let json = JSON.parse(Buffer.concat(buffer).toString()); - if (Array.isArray(json)) { - resolve(json.map(o => o.slug)); - return; - } - reject(`Unexpected data format. Response code: ${res.statusCode}.`); - } - else { - reject(`No resources in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resources in ${project} with the following error: ${err}. ${options.path}`); - }); - request.end(); - }); -} -function findObsoleteResources(apiHostname, username, password) { - let resourcesByProject = Object.create(null); - resourcesByProject[extensionsProject] = [].concat(exports.externalExtensionsWithTranslations); // clone - return (0, event_stream_1.through)(function (file) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - let slugs = resourcesByProject[project]; - if (!slugs) { - resourcesByProject[project] = slugs = []; - } - slugs.push(slug); - this.push(file); - }, function () { - const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); - let i18Resources = [...json.editor, ...json.workbench].map((r) => r.project + '/' + r.name.replace(/\//g, '_')); - let extractedResources = []; - for (let project of [workbenchProject, editorProject]) { - for (let resource of resourcesByProject[project]) { - if (resource !== 'setup_messages') { - extractedResources.push(project + '/' + resource); - } - } - } - if (i18Resources.length !== extractedResources.length) { - console.log(`[i18n] Obsolete resources in file 'build/lib/i18n.resources.json': JSON.stringify(${i18Resources.filter(p => extractedResources.indexOf(p) === -1)})`); - console.log(`[i18n] Missing resources in file 'build/lib/i18n.resources.json': JSON.stringify(${extractedResources.filter(p => i18Resources.indexOf(p) === -1)})`); - } - let promises = []; - for (let project in resourcesByProject) { - promises.push(getAllResources(project, apiHostname, username, password).then(resources => { - let expectedResources = resourcesByProject[project]; - let unusedResources = resources.filter(resource => resource && expectedResources.indexOf(resource) === -1); - if (unusedResources.length) { - console.log(`[transifex] Obsolete resources in project '${project}': ${unusedResources.join(', ')}`); - } - })); - } - return Promise.all(promises).then(_ => { - this.push(null); - }).catch((reason) => { throw new Error(reason); }); - }); -} -exports.findObsoleteResources = findObsoleteResources; -function tryGetResource(project, slug, apiHostname, credentials) { - return new Promise((resolve, reject) => { - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/?details`, - auth: credentials, - method: 'GET' - }; - const request = https.request(options, (response) => { - if (response.statusCode === 404) { - resolve(false); - } - else if (response.statusCode === 200) { - resolve(true); - } - else { - reject(`Failed to query resource ${project}/${slug}. Response: ${response.statusCode} ${response.statusMessage}`); - } - }); - request.on('error', (err) => { - reject(`Failed to get ${project}/${slug} on Transifex: ${err}`); - }); - request.end(); - }); -} -function createResource(project, slug, xlfFile, apiHostname, credentials) { - return new Promise((_resolve, reject) => { - const data = JSON.stringify({ - 'content': xlfFile.contents.toString(), - 'name': slug, - 'slug': slug, - 'i18n_type': 'XLIFF' - }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'POST' - }; - let request = https.request(options, (res) => { - if (res.statusCode === 201) { - log(`Resource ${project}/${slug} successfully created on Transifex.`); - } - else { - reject(`Something went wrong in the request creating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to create ${project}/${slug} on Transifex: ${err}`); - }); - request.write(data); - request.end(); - }); -} -/** - * The following link provides information about how Transifex handles updates of a resource file: - * https://dev.befoolish.co/tx-docs/public/projects/updating-content#what-happens-when-you-update-files - */ -function updateResource(project, slug, xlfFile, apiHostname, credentials) { - return new Promise((resolve, reject) => { - const data = JSON.stringify({ content: xlfFile.contents.toString() }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/content`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'PUT' - }; - let request = https.request(options, (res) => { - if (res.statusCode === 200) { - res.setEncoding('utf8'); - let responseBuffer = ''; - res.on('data', function (chunk) { - responseBuffer += chunk; - }); - res.on('end', () => { - const response = JSON.parse(responseBuffer); - log(`Resource ${project}/${slug} successfully updated on Transifex. Strings added: ${response.strings_added}, updated: ${response.strings_added}, deleted: ${response.strings_added}`); - resolve(); - }); - } - else { - reject(`Something went wrong in the request updating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to update ${project}/${slug} on Transifex: ${err}`); - }); - request.write(data); - request.end(); - }); -} -function pullSetupXlfFiles(apiHostname, username, password, language, includeDefault) { - let setupResources = [{ name: 'setup_messages', project: workbenchProject }]; - if (includeDefault) { - setupResources.push({ name: 'setup_default', project: setupProject }); - } - return pullXlfFiles(apiHostname, username, password, language, setupResources); -} -exports.pullSetupXlfFiles = pullSetupXlfFiles; -function pullXlfFiles(apiHostname, username, password, language, resources) { - const credentials = `${username}:${password}`; - let expectedTranslationsCount = resources.length; - let translationsRetrieved = 0, called = false; - return (0, event_stream_1.readable)(function (_count, callback) { - // Mark end of stream when all resources were retrieved - if (translationsRetrieved === expectedTranslationsCount) { - return this.emit('end'); - } - if (!called) { - called = true; - const stream = this; - resources.map(function (resource) { - retrieveResource(language, resource, apiHostname, credentials).then((file) => { - if (file) { - stream.emit('data', file); - } - translationsRetrieved++; - }).catch(error => { throw new Error(error); }); - }); - } - callback(); - }); -} -const limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); -function retrieveResource(language, resource, apiHostname, credentials) { - return limiter.queue(() => new Promise((resolve, reject) => { - const slug = resource.name.replace(/\//g, '_'); - const project = resource.project; - let transifexLanguageId = language.id === 'ps' ? 'en' : language.translationId || language.id; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, - auth: credentials, - port: 443, - method: 'GET' - }; - console.log('[transifex] Fetching ' + options.path); - let request = https.request(options, (res) => { - let xlfBuffer = []; - res.on('data', (chunk) => xlfBuffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); - } - else if (res.statusCode === 404) { - console.log(`[transifex] ${slug} in ${project} returned no data.`); - resolve(null); - } - else { - reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); - }); - request.end(); - })); -} -function prepareI18nFiles() { - let parsePromises = []; - return (0, event_stream_1.through)(function (xlf) { - let stream = this; - let parsePromise = XLF.parse(xlf.contents.toString()); - parsePromises.push(parsePromise); - parsePromise.then(resolvedFiles => { - resolvedFiles.forEach(file => { - let translatedFile = createI18nFile(file.originalFilePath, file.messages); - stream.queue(translatedFile); - }); - }); - }, function () { - Promise.all(parsePromises) - .then(() => { this.queue(null); }) - .catch(reason => { throw new Error(reason); }); - }); -} -exports.prepareI18nFiles = prepareI18nFiles; -function createI18nFile(originalFilePath, messages) { - let result = Object.create(null); +function createI18nFile(name, messages) { + const result = Object.create(null); result[''] = [ '--------------------------------------------------------------------------------------------', 'Copyright (c) Microsoft Corporation. All rights reserved.', @@ -998,7 +669,7 @@ function createI18nFile(originalFilePath, messages) { '--------------------------------------------------------------------------------------------', 'Do not edit this file. It is machine generated.' ]; - for (let key of Object.keys(messages)) { + for (const key of Object.keys(messages)) { result[key] = messages[key]; } let content = JSON.stringify(result, null, '\t'); @@ -1006,43 +677,51 @@ function createI18nFile(originalFilePath, messages) { content = content.replace(/\n/g, '\r\n'); } return new File({ - path: path.join(originalFilePath + '.i18n.json'), + path: path.join(name + '.i18n.json'), contents: Buffer.from(content, 'utf8') }); } const i18nPackVersion = '1.0.0'; -function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pseudo = false) { - let parsePromises = []; - let mainPack = { version: i18nPackVersion, contents: {} }; - let extensionsPacks = {}; - let errors = []; +function getRecordFromL10nJsonFormat(l10nJsonFormat) { + const record = {}; + for (const key of Object.keys(l10nJsonFormat)) { + const value = l10nJsonFormat[key]; + record[key] = typeof value === 'string' ? value : value.message; + } + return record; +} +function prepareI18nPackFiles(resultingTranslationPaths) { + const parsePromises = []; + const mainPack = { version: i18nPackVersion, contents: {} }; + const extensionsPacks = {}; + const errors = []; return (0, event_stream_1.through)(function (xlf) { - let project = path.basename(path.dirname(path.dirname(xlf.relative))); - let resource = path.basename(xlf.relative, '.xlf'); - let contents = xlf.contents.toString(); + const project = path.basename(path.dirname(path.dirname(xlf.relative))); + const resource = path.basename(xlf.relative, '.xlf'); + const contents = xlf.contents.toString(); log(`Found ${project}: ${resource}`); - let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); + const parsePromise = (0, l10n_dev_1.getL10nFilesFromXlf)(contents); parsePromises.push(parsePromise); parsePromise.then(resolvedFiles => { resolvedFiles.forEach(file => { - const path = file.originalFilePath; + const path = file.name; const firstSlash = path.indexOf('/'); if (project === extensionsProject) { let extPack = extensionsPacks[resource]; if (!extPack) { extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} }; } - const externalId = externalExtensions[resource]; + const externalId = externalExtensionsWithTranslations[resource]; if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent const secondSlash = path.indexOf('/', firstSlash + 1); - extPack.contents[path.substr(secondSlash + 1)] = file.messages; + extPack.contents[path.substring(secondSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); } else { - extPack.contents[path] = file.messages; + extPack.contents[path] = getRecordFromL10nJsonFormat(file.messages); } } else { - mainPack.contents[path.substr(firstSlash + 1)] = file.messages; + mainPack.contents[path.substring(firstSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); } }); }).catch(reason => { @@ -1057,10 +736,10 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pse const translatedMainFile = createI18nFile('./main', mainPack); resultingTranslationPaths.push({ id: 'vscode', resourceName: 'main.i18n.json' }); this.queue(translatedMainFile); - for (let extension in extensionsPacks) { + for (const extension in extensionsPacks) { const translatedExtFile = createI18nFile(`extensions/${extension}`, extensionsPacks[extension]); this.queue(translatedExtFile); - const externalExtensionId = externalExtensions[extension]; + const externalExtensionId = externalExtensionsWithTranslations[extension]; if (externalExtensionId) { resultingTranslationPaths.push({ id: externalExtensionId, resourceName: `extensions/${extension}.i18n.json` }); } @@ -1077,14 +756,14 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pse } exports.prepareI18nPackFiles = prepareI18nPackFiles; function prepareIslFiles(language, innoSetupConfig) { - let parsePromises = []; + const parsePromises = []; return (0, event_stream_1.through)(function (xlf) { - let stream = this; - let parsePromise = XLF.parse(xlf.contents.toString()); + const stream = this; + const parsePromise = XLF.parse(xlf.contents.toString()); parsePromises.push(parsePromise); parsePromise.then(resolvedFiles => { resolvedFiles.forEach(file => { - let translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); + const translatedFile = createIslFile(file.name, file.messages, language, innoSetupConfig); stream.queue(translatedFile); }); }).catch(reason => { @@ -1099,27 +778,27 @@ function prepareIslFiles(language, innoSetupConfig) { }); } exports.prepareIslFiles = prepareIslFiles; -function createIslFile(originalFilePath, messages, language, innoSetup) { - let content = []; +function createIslFile(name, messages, language, innoSetup) { + const content = []; let originalContent; - if (path.basename(originalFilePath) === 'Default') { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.isl', 'utf8')); + if (path.basename(name) === 'Default') { + originalContent = new TextModel(fs.readFileSync(name + '.isl', 'utf8')); } else { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.en.isl', 'utf8')); + originalContent = new TextModel(fs.readFileSync(name + '.en.isl', 'utf8')); } originalContent.lines.forEach(line => { if (line.length > 0) { - let firstChar = line.charAt(0); + const firstChar = line.charAt(0); if (firstChar === '[' || firstChar === ';') { content.push(line); } else { - let sections = line.split('='); - let key = sections[0]; + const sections = line.split('='); + const key = sections[0]; let translated = line; if (key) { - let translatedMessage = messages[key]; + const translatedMessage = messages[key]; if (translatedMessage) { translated = `${key}=${translatedMessage}`; } @@ -1128,7 +807,7 @@ function createIslFile(originalFilePath, messages, language, innoSetup) { } } }); - const basename = path.basename(originalFilePath); + const basename = path.basename(name); const filePath = `${basename}.${language.id}.isl`; const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage); return new File({ @@ -1137,9 +816,9 @@ function createIslFile(originalFilePath, messages, language, innoSetup) { }); } function encodeEntities(value) { - let result = []; + const result = []; for (let i = 0; i < value.length; i++) { - let ch = value[i]; + const ch = value[i]; switch (ch) { case '<': result.push('<'); @@ -1159,6 +838,3 @@ function encodeEntities(value) { function decodeEntities(value) { return value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); } -function pseudify(message) { - return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; -} diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index b7b2cd1833e..fa8f6fc1feb 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -90,6 +90,10 @@ "name": "vs/workbench/contrib/files", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/folding", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/html", "project": "vscode-workbench" @@ -278,6 +282,10 @@ "name": "vs/workbench/contrib/userDataSync", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/editSessions", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/views", "project": "vscode-workbench" @@ -290,10 +298,22 @@ "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" }, + { + "name": "vs/workbench/contrib/remoteTunnel", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/actions", "project": "vscode-workbench" @@ -426,6 +446,10 @@ "name": "vs/workbench/services/userDataSync", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/editSessions", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/views", "project": "vscode-workbench" @@ -455,11 +479,11 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/contrib/profiles", + "name": "vs/workbench/contrib/userDataProfile", "project": "vscode-profiles" }, { - "name": "vs/workbench/services/profiles", + "name": "vs/workbench/services/userDataProfile", "project": "vscode-profiles" } ] diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 3ea4f7efb4e..1962ba98926 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -6,17 +6,15 @@ import * as path from 'path'; import * as fs from 'fs'; -import { through, readable, ThroughStream } from 'event-stream'; +import { merge, through, ThroughStream, writeArray } from 'event-stream'; import * as File from 'vinyl'; import * as Is from 'is'; import * as xml2js from 'xml2js'; -import * as https from 'https'; import * as gulp from 'gulp'; import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; import * as iconv from '@vscode/iconv-lite-umd'; - -const NUMBER_OF_CONCURRENT_DOWNLOADS = 4; +import { l10nJsonFormat, getL10nXlf, l10nJsonDetails, getL10nFilesFromXlf, getL10nJson } from '@vscode/l10n-dev'; function log(message: any, ...rest: any[]): void { fancyLog(ansiColors.green('[i18n]'), message, ...rest); @@ -52,17 +50,12 @@ export const extraLanguages: Language[] = [ ]; // non built-in extensions also that are transifex and need to be part of the language packs -export const externalExtensionsWithTranslations = { +const externalExtensionsWithTranslations: Record = { 'vscode-chrome-debug': 'msjsdiag.debugger-for-chrome', 'vscode-node-debug': 'ms-vscode.node-debug', 'vscode-node-debug2': 'ms-vscode.node-debug2' }; - -interface Map { - [key: string]: V; -} - interface Item { id: string; message: string; @@ -74,12 +67,6 @@ export interface Resource { project: string; } -interface ParsedXLF { - messages: Map; - originalFilePath: string; - language: string; -} - interface LocalizeInfo { key: string; comment: string[]; @@ -87,15 +74,15 @@ interface LocalizeInfo { module LocalizeInfo { export function is(value: any): value is LocalizeInfo { - let candidate = value as LocalizeInfo; + const candidate = value as LocalizeInfo; return Is.defined(candidate) && Is.string(candidate.key) && (Is.undef(candidate.comment) || (Is.array(candidate.comment) && candidate.comment.every(element => Is.string(element)))); } } interface BundledFormat { - keys: Map<(string | LocalizeInfo)[]>; - messages: Map; - bundles: Map; + keys: Record; + messages: Record; + bundles: Record; } module BundledFormat { @@ -104,34 +91,13 @@ module BundledFormat { return false; } - let candidate = value as BundledFormat; - let length = Object.keys(value).length; + const candidate = value as BundledFormat; + const length = Object.keys(value).length; return length === 3 && Is.defined(candidate.keys) && Is.defined(candidate.messages) && Is.defined(candidate.bundles); } } -interface ValueFormat { - message: string; - comment: string[]; -} - -interface PackageJsonFormat { - [key: string]: string | ValueFormat; -} - -module PackageJsonFormat { - export function is(value: any): value is PackageJsonFormat { - if (Is.undef(value) || !Is.object(value)) { - return false; - } - return Object.keys(value).every(key => { - let element = value[key]; - return Is.string(element) || (Is.object(element) && Is.defined(element.message) && Is.defined(element.comment)); - }); - } -} - interface BundledExtensionFormat { [key: string]: { messages: string[]; @@ -181,7 +147,7 @@ class TextModel { export class XLF { private buffer: string[]; - private files: Map; + private files: Record; public numberOfMessages: number; constructor(public project: string) { @@ -218,9 +184,9 @@ export class XLF { } this.numberOfMessages += keys.length; this.files[original] = []; - let existingKeys = new Set(); + const existingKeys = new Set(); for (let i = 0; i < keys.length; i++) { - let key = keys[i]; + const key = keys[i]; let realKey: string | undefined; let comment: string | undefined; if (Is.string(key)) { @@ -236,7 +202,7 @@ export class XLF { continue; } existingKeys.add(realKey); - let message: string = encodeEntities(messages[i]); + const message: string = encodeEntities(messages[i]); this.files[original].push({ id: realKey, message: message, comment: comment }); } } @@ -269,42 +235,16 @@ export class XLF { } private appendNewLine(content: string, indent?: number): void { - let line = new Line(indent); + const line = new Line(indent); line.append(content); this.buffer.push(line.toString()); } - static parsePseudo = function (xlfString: string): Promise { - return new Promise((resolve) => { - let parser = new xml2js.Parser(); - let files: { messages: Map; originalFilePath: string; language: string }[] = []; - parser.parseString(xlfString, function (_err: any, result: any) { - const fileNodes: any[] = result['xliff']['file']; - fileNodes.forEach(file => { - const originalFilePath = file.$.original; - const messages: Map = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit: any) => { - const key = unit.$.id; - const val = pseudify(unit.source[0]['_'].toString()); - if (key && val) { - messages[key] = decodeEntities(val); - } - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); - } - }); - resolve(files); - }); - }); - }; - - static parse = function (xlfString: string): Promise { + static parse = function (xlfString: string): Promise { return new Promise((resolve, reject) => { - let parser = new xml2js.Parser(); + const parser = new xml2js.Parser(); - let files: { messages: Map; originalFilePath: string; language: string }[] = []; + const files: { messages: Record; name: string; language: string }[] = []; parser.parseString(xlfString, function (err: any, result: any) { if (err) { @@ -317,15 +257,15 @@ export class XLF { } fileNodes.forEach((file) => { - const originalFilePath = file.$.original; - if (!originalFilePath) { + const name = file.$.original; + if (!name) { reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); } - let language = file.$['target-language']; + const language = file.$['target-language']; if (!language) { reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); } - const messages: Map = {}; + const messages: Record = {}; const transUnits = file.body[0]['trans-unit']; if (transUnits) { @@ -341,12 +281,12 @@ export class XLF { val = val._ ? val._ : ''; } if (!key) { - reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${originalFilePath} is missing the ID attribute.`)); + reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${name} is missing the ID attribute.`)); return; } messages[key] = decodeEntities(val); }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); + files.push({ messages, name, language: language.toLowerCase() }); } }); @@ -356,49 +296,6 @@ export class XLF { }; } -export interface ITask { - (): T; -} - -interface ILimitedTaskFactory { - factory: ITask>; - c: (value?: T | Promise) => void; - e: (error?: any) => void; -} - -export class Limiter { - private runningPromises: number; - private outstandingPromises: ILimitedTaskFactory[]; - - constructor(private maxDegreeOfParalellism: number) { - this.outstandingPromises = []; - this.runningPromises = 0; - } - - queue(factory: ITask>): Promise { - return new Promise((c, e) => { - this.outstandingPromises.push({ factory, c, e }); - this.consume(); - }); - } - - private consume(): void { - while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { - const iLimitedTask = this.outstandingPromises.shift()!; - this.runningPromises++; - - const promise = iLimitedTask.factory(); - promise.then(iLimitedTask.c).catch(iLimitedTask.e); - promise.then(() => this.consumed()).catch(() => this.consumed()); - } - } - - private consumed(): void { - this.runningPromises--; - this.consume(); - } -} - function sortLanguages(languages: Language[]): Language[] { return languages.sort((a: Language, b: Language): number => { return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); @@ -412,9 +309,10 @@ function stripComments(content: string): string { // Second group matches a single quoted string // Third group matches a multi line comment // Forth group matches a single line comment - const regexp = /("[^"\\]*(?:\\.[^"\\]*)*")|('[^'\\]*(?:\\.[^'\\]*)*')|(\/\*[^\/\*]*(?:(?:\*|\/)[^\/\*]*)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; - let result = content.replace(regexp, (match, _m1: string, _m2: string, m3: string, m4: string) => { - // Only one of m1, m2, m3, m4 matches + // Fifth group matches a trailing comma + const regexp = /("[^"\\]*(?:\\.[^"\\]*)*")|('[^'\\]*(?:\\.[^'\\]*)*')|(\/\*[^\/\*]*(?:(?:\*|\/)[^\/\*]*)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))|(,\s*[}\]])/g; + const result = content.replace(regexp, (match, _m1: string, _m2: string, m3: string, m4: string, m5: string) => { + // Only one of m1, m2, m3, m4, m5 matches if (m3) { // A block comment. Replace with nothing return ''; @@ -427,6 +325,9 @@ function stripComments(content: string): string { } else { return ''; } + } else if (m5) { + // Remove the trailing comma + return match.substring(1); } else { // We match a string return match; @@ -472,22 +373,22 @@ function escapeCharacters(value: string): string { } function processCoreBundleFormat(fileHeader: string, languages: Language[], json: BundledFormat, emitter: ThroughStream) { - let keysSection = json.keys; - let messageSection = json.messages; - let bundleSection = json.bundles; + const keysSection = json.keys; + const messageSection = json.messages; + const bundleSection = json.bundles; - let statistics: Map = Object.create(null); + const statistics: Record = Object.create(null); - let defaultMessages: Map> = Object.create(null); - let modules = Object.keys(keysSection); + const defaultMessages: Record> = Object.create(null); + const modules = Object.keys(keysSection); modules.forEach((module) => { - let keys = keysSection[module]; - let messages = messageSection[module]; + const keys = keysSection[module]; + const messages = messageSection[module]; if (!messages || keys.length !== messages.length) { emitter.emit('error', `Message for module ${module} corrupted. Mismatch in number of keys and messages.`); return; } - let messageMap: Map = Object.create(null); + const messageMap: Record = Object.create(null); defaultMessages[module] = messageMap; keys.map((key, i) => { if (typeof key === 'string') { @@ -498,28 +399,28 @@ function processCoreBundleFormat(fileHeader: string, languages: Language[], json }); }); - let languageDirectory = path.join(__dirname, '..', '..', '..', 'vscode-loc', 'i18n'); + const languageDirectory = path.join(__dirname, '..', '..', '..', 'vscode-loc', 'i18n'); if (!fs.existsSync(languageDirectory)) { log(`No VS Code localization repository found. Looking at ${languageDirectory}`); log(`To bundle translations please check out the vscode-loc repository as a sibling of the vscode repository.`); } - let sortedLanguages = sortLanguages(languages); + const sortedLanguages = sortLanguages(languages); sortedLanguages.forEach((language) => { if (process.env['VSCODE_BUILD_VERBOSE']) { log(`Generating nls bundles for: ${language.id}`); } statistics[language.id] = 0; - let localizedModules: Map = Object.create(null); - let languageFolderName = language.translationId || language.id; - let i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); + const localizedModules: Record = Object.create(null); + const languageFolderName = language.translationId || language.id; + const i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); let allMessages: I18nFormat | undefined; if (fs.existsSync(i18nFile)) { - let content = stripComments(fs.readFileSync(i18nFile, 'utf8')); + const content = stripComments(fs.readFileSync(i18nFile, 'utf8')); allMessages = JSON.parse(content); } modules.forEach((module) => { - let order = keysSection[module]; + const order = keysSection[module]; let moduleMessage: { [messageKey: string]: string } | undefined; if (allMessages) { moduleMessage = allMessages.contents[module]; @@ -531,7 +432,7 @@ function processCoreBundleFormat(fileHeader: string, languages: Language[], json moduleMessage = defaultMessages[module]; statistics[language.id] = statistics[language.id] + Object.keys(moduleMessage).length; } - let localizedMessages: string[] = []; + const localizedMessages: string[] = []; order.forEach((keyInfo) => { let key: string | null = null; if (typeof keyInfo === 'string') { @@ -552,14 +453,14 @@ function processCoreBundleFormat(fileHeader: string, languages: Language[], json localizedModules[module] = localizedMessages; }); Object.keys(bundleSection).forEach((bundle) => { - let modules = bundleSection[bundle]; - let contents: string[] = [ + const modules = bundleSection[bundle]; + const contents: string[] = [ fileHeader, `define("${bundle}.nls.${language.id}", {` ]; modules.forEach((module, index) => { contents.push(`\t"${module}": [`); - let messages = localizedModules[module]; + const messages = localizedModules[module]; if (!messages) { emitter.emit('error', `Didn't find messages for module ${module}.`); return; @@ -574,11 +475,11 @@ function processCoreBundleFormat(fileHeader: string, languages: Language[], json }); }); Object.keys(statistics).forEach(key => { - let value = statistics[key]; + const value = statistics[key]; log(`${key} has ${value} untranslated strings.`); }); sortedLanguages.forEach(language => { - let stats = statistics[language.id]; + const stats = statistics[language.id]; if (Is.undef(stats)) { log(`\tNo translations found for language ${language.id}. Using default language instead.`); } @@ -587,7 +488,7 @@ function processCoreBundleFormat(fileHeader: string, languages: Language[], json export function processNlsFiles(opts: { fileHeader: string; languages: Language[] }): ThroughStream { return through(function (this: ThroughStream, file: File) { - let fileName = path.basename(file.path); + const fileName = path.basename(file.path); if (fileName === 'nls.metadata.json') { let json = null; if (file.isBuffer()) { @@ -607,7 +508,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; @@ -622,6 +524,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 }; @@ -641,9 +545,9 @@ export function createXlfFilesForCoreBundle(): ThroughStream { const basename = path.basename(file.path); if (basename === 'nls.metadata.json') { if (file.isBuffer()) { - const xlfs: Map = Object.create(null); + const xlfs: Record = Object.create(null); const json: BundledFormat = JSON.parse((file.contents as Buffer).toString('utf8')); - for (let coreModule in json.keys) { + for (const coreModule in json.keys) { const projectResource = getResource(coreModule); const resource = projectResource.name; const project = projectResource.project; @@ -662,7 +566,7 @@ export function createXlfFilesForCoreBundle(): ThroughStream { xlf.addFile(`src/${coreModule}`, keys, messages); } } - for (let resource in xlfs) { + for (const resource in xlfs) { const xlf = xlfs[resource]; const filePath = `${xlf.project}/${resource.replace(/\//g, '_')}.xlf`; const xlfFile = new File({ @@ -682,6 +586,32 @@ export function createXlfFilesForCoreBundle(): ThroughStream { }); } +function createL10nBundleForExtension(extensionName: string): ThroughStream { + const result = through(); + gulp.src([ + `extensions/${extensionName}/src/**/*.ts`, + ]).pipe(writeArray((err, files: File[]) => { + if (err) { + result.emit('error', err); + return; + } + + const json = getL10nJson(files.map(file => { + return file.contents.toString('utf8'); + })); + + if (Object.keys(json).length > 0) { + result.emit('data', new File({ + path: `${extensionName}/bundle.l10n.json`, + contents: Buffer.from(JSON.stringify(json), 'utf8') + })); + } + result.emit('end'); + })); + + return result; +} + export function createXlfFilesForExtensions(): ThroughStream { let counter: number = 0; let folderStreamEnded: boolean = false; @@ -692,53 +622,57 @@ export function createXlfFilesForExtensions(): ThroughStream { if (!stat.isDirectory()) { return; } - let extensionName = path.basename(extensionFolder.path); + const extensionName = path.basename(extensionFolder.path); if (extensionName === 'node_modules') { return; } counter++; - let _xlf: XLF; - function getXlf() { - if (!_xlf) { - _xlf = new XLF(extensionsProject); + let _l10nMap: Map; + function getL10nMap() { + if (!_l10nMap) { + _l10nMap = new Map(); } - return _xlf; + return _l10nMap; } - gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(through(function (file: File) { + merge( + gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }), + createL10nBundleForExtension(extensionName) + ).pipe(through(function (file: File) { if (file.isBuffer()) { const buffer: Buffer = file.contents as Buffer; const basename = path.basename(file.path); if (basename === 'package.nls.json') { - const json: PackageJsonFormat = JSON.parse(buffer.toString('utf8')); - const keys = Object.keys(json); - const messages = keys.map((key) => { - const value = json[key]; - if (Is.string(value)) { - return value; - } else if (value) { - return value.message; - } else { - return `Unknown message for key: ${key}`; - } - }); - getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); + const json: l10nJsonFormat = JSON.parse(buffer.toString('utf8')); + getL10nMap().set(`extensions/${extensionName}/package`, json); } else if (basename === 'nls.metadata.json') { const json: BundledExtensionFormat = JSON.parse(buffer.toString('utf8')); const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); - for (let file in json) { + for (const file in json) { const fileContent = json[file]; - getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); + const info: l10nJsonFormat = Object.create(null); + for (let i = 0; i < fileContent.messages.length; i++) { + const message = fileContent.messages[i]; + const { key, comment } = LocalizeInfo.is(fileContent.keys[i]) + ? fileContent.keys[i] as LocalizeInfo + : { key: fileContent.keys[i] as string, comment: undefined }; + + info[key] = comment ? { message, comment } : message; + } + getL10nMap().set(`extensions/${extensionName}/${relPath}/${file}`, info); } + } else if (basename === 'bundle.l10n.json') { + const json: l10nJsonFormat = JSON.parse(buffer.toString('utf8')); + getL10nMap().set(`extensions/${extensionName}/bundle`, json); } else { this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); return; } } }, function () { - if (_xlf) { - let xlfFile = new File({ + if (_l10nMap?.size > 0) { + const xlfFile = new File({ path: path.join(extensionsProject, extensionName + '.xlf'), - contents: Buffer.from(_xlf.toString(), 'utf8') + contents: Buffer.from(getL10nXlf(_l10nMap), 'utf8') }); folderStream.queue(xlfFile); } @@ -769,17 +703,17 @@ export function createXlfFilesForIsl(): ThroughStream { throw new Error(`Unknown input file ${file.path}`); } - let xlf = new XLF(projectName), + const xlf = new XLF(projectName), keys: string[] = [], messages: string[] = []; - let model = new TextModel(file.contents.toString()); + const model = new TextModel(file.contents.toString()); let inMessageSection = false; model.lines.forEach(line => { if (line.length === 0) { return; } - let firstChar = line.charAt(0); + const firstChar = line.charAt(0); switch (firstChar) { case ';': // Comment line; @@ -791,12 +725,12 @@ export function createXlfFilesForIsl(): ThroughStream { if (!inMessageSection) { return; } - let sections: string[] = line.split('='); + const sections: string[] = line.split('='); if (sections.length !== 2) { throw new Error(`Badly formatted message found: ${line}`); } else { - let key = sections[0]; - let value = sections[1]; + const key = sections[0]; + const value = sections[1]; if (key.length > 0 && value.length > 0) { keys.push(key); messages.push(value); @@ -814,322 +748,8 @@ export function createXlfFilesForIsl(): ThroughStream { }); } -export function pushXlfFiles(apiHostname: string, username: string, password: string): ThroughStream { - let tryGetPromises: Array> = []; - let updateCreatePromises: Array> = []; - - return through(function (this: ThroughStream, file: File) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - const credentials = `${username}:${password}`; - - // Check if resource already exists, if not, then create it. - let promise = tryGetResource(project, slug, apiHostname, credentials); - tryGetPromises.push(promise); - promise.then(exists => { - if (exists) { - promise = updateResource(project, slug, file, apiHostname, credentials); - } else { - promise = createResource(project, slug, file, apiHostname, credentials); - } - updateCreatePromises.push(promise); - }); - - }, function () { - // End the pipe only after all the communication with Transifex API happened - Promise.all(tryGetPromises).then(() => { - Promise.all(updateCreatePromises).then(() => { - this.queue(null); - }).catch((reason) => { throw new Error(reason); }); - }).catch((reason) => { throw new Error(reason); }); - }); -} - -function getAllResources(project: string, apiHostname: string, username: string, password: string): Promise { - return new Promise((resolve, reject) => { - const credentials = `${username}:${password}`; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - auth: credentials, - method: 'GET' - }; - - const request = https.request(options, (res) => { - let buffer: Buffer[] = []; - res.on('data', (chunk: Buffer) => buffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - let json = JSON.parse(Buffer.concat(buffer).toString()); - if (Array.isArray(json)) { - resolve(json.map(o => o.slug)); - return; - } - reject(`Unexpected data format. Response code: ${res.statusCode}.`); - } else { - reject(`No resources in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resources in ${project} with the following error: ${err}. ${options.path}`); - }); - request.end(); - }); -} - -export function findObsoleteResources(apiHostname: string, username: string, password: string): ThroughStream { - let resourcesByProject: Map = Object.create(null); - resourcesByProject[extensionsProject] = ([] as any[]).concat(externalExtensionsWithTranslations); // clone - - return through(function (this: ThroughStream, file: File) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - - let slugs = resourcesByProject[project]; - if (!slugs) { - resourcesByProject[project] = slugs = []; - } - slugs.push(slug); - this.push(file); - }, function () { - - const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); - let i18Resources = [...json.editor, ...json.workbench].map((r: Resource) => r.project + '/' + r.name.replace(/\//g, '_')); - let extractedResources: string[] = []; - for (let project of [workbenchProject, editorProject]) { - for (let resource of resourcesByProject[project]) { - if (resource !== 'setup_messages') { - extractedResources.push(project + '/' + resource); - } - } - } - if (i18Resources.length !== extractedResources.length) { - console.log(`[i18n] Obsolete resources in file 'build/lib/i18n.resources.json': JSON.stringify(${i18Resources.filter(p => extractedResources.indexOf(p) === -1)})`); - console.log(`[i18n] Missing resources in file 'build/lib/i18n.resources.json': JSON.stringify(${extractedResources.filter(p => i18Resources.indexOf(p) === -1)})`); - } - - let promises: Array> = []; - for (let project in resourcesByProject) { - promises.push( - getAllResources(project, apiHostname, username, password).then(resources => { - let expectedResources = resourcesByProject[project]; - let unusedResources = resources.filter(resource => resource && expectedResources.indexOf(resource) === -1); - if (unusedResources.length) { - console.log(`[transifex] Obsolete resources in project '${project}': ${unusedResources.join(', ')}`); - } - }) - ); - } - return Promise.all(promises).then(_ => { - this.push(null); - }).catch((reason) => { throw new Error(reason); }); - }); -} - -function tryGetResource(project: string, slug: string, apiHostname: string, credentials: string): Promise { - return new Promise((resolve, reject) => { - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/?details`, - auth: credentials, - method: 'GET' - }; - - const request = https.request(options, (response) => { - if (response.statusCode === 404) { - resolve(false); - } else if (response.statusCode === 200) { - resolve(true); - } else { - reject(`Failed to query resource ${project}/${slug}. Response: ${response.statusCode} ${response.statusMessage}`); - } - }); - request.on('error', (err) => { - reject(`Failed to get ${project}/${slug} on Transifex: ${err}`); - }); - - request.end(); - }); -} - -function createResource(project: string, slug: string, xlfFile: File, apiHostname: string, credentials: any): Promise { - return new Promise((_resolve, reject) => { - const data = JSON.stringify({ - 'content': xlfFile.contents.toString(), - 'name': slug, - 'slug': slug, - 'i18n_type': 'XLIFF' - }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'POST' - }; - - let request = https.request(options, (res) => { - if (res.statusCode === 201) { - log(`Resource ${project}/${slug} successfully created on Transifex.`); - } else { - reject(`Something went wrong in the request creating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to create ${project}/${slug} on Transifex: ${err}`); - }); - - request.write(data); - request.end(); - }); -} - -/** - * The following link provides information about how Transifex handles updates of a resource file: - * https://dev.befoolish.co/tx-docs/public/projects/updating-content#what-happens-when-you-update-files - */ -function updateResource(project: string, slug: string, xlfFile: File, apiHostname: string, credentials: string): Promise { - return new Promise((resolve, reject) => { - const data = JSON.stringify({ content: xlfFile.contents.toString() }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/content`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'PUT' - }; - - let request = https.request(options, (res) => { - if (res.statusCode === 200) { - res.setEncoding('utf8'); - - let responseBuffer: string = ''; - res.on('data', function (chunk) { - responseBuffer += chunk; - }); - res.on('end', () => { - const response = JSON.parse(responseBuffer); - log(`Resource ${project}/${slug} successfully updated on Transifex. Strings added: ${response.strings_added}, updated: ${response.strings_added}, deleted: ${response.strings_added}`); - resolve(); - }); - } else { - reject(`Something went wrong in the request updating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to update ${project}/${slug} on Transifex: ${err}`); - }); - - request.write(data); - request.end(); - }); -} - -export function pullSetupXlfFiles(apiHostname: string, username: string, password: string, language: Language, includeDefault: boolean): NodeJS.ReadableStream { - let setupResources = [{ name: 'setup_messages', project: workbenchProject }]; - if (includeDefault) { - setupResources.push({ name: 'setup_default', project: setupProject }); - } - return pullXlfFiles(apiHostname, username, password, language, setupResources); -} - -function pullXlfFiles(apiHostname: string, username: string, password: string, language: Language, resources: Resource[]): NodeJS.ReadableStream { - const credentials = `${username}:${password}`; - let expectedTranslationsCount = resources.length; - let translationsRetrieved = 0, called = false; - - return readable(function (_count: any, callback: any) { - // Mark end of stream when all resources were retrieved - if (translationsRetrieved === expectedTranslationsCount) { - return this.emit('end'); - } - - if (!called) { - called = true; - const stream = this; - resources.map(function (resource) { - retrieveResource(language, resource, apiHostname, credentials).then((file: File | null) => { - if (file) { - stream.emit('data', file); - } - translationsRetrieved++; - }).catch(error => { throw new Error(error); }); - }); - } - - callback(); - }); -} -const limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); - -function retrieveResource(language: Language, resource: Resource, apiHostname: string, credentials: string): Promise { - return limiter.queue(() => new Promise((resolve, reject) => { - const slug = resource.name.replace(/\//g, '_'); - const project = resource.project; - let transifexLanguageId = language.id === 'ps' ? 'en' : language.translationId || language.id; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, - auth: credentials, - port: 443, - method: 'GET' - }; - console.log('[transifex] Fetching ' + options.path); - - let request = https.request(options, (res) => { - let xlfBuffer: Buffer[] = []; - res.on('data', (chunk: Buffer) => xlfBuffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); - } else if (res.statusCode === 404) { - console.log(`[transifex] ${slug} in ${project} returned no data.`); - resolve(null); - } else { - reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); - }); - request.end(); - })); -} - -export function prepareI18nFiles(): ThroughStream { - let parsePromises: Promise[] = []; - - return through(function (this: ThroughStream, xlf: File) { - let stream = this; - let parsePromise = XLF.parse(xlf.contents.toString()); - parsePromises.push(parsePromise); - parsePromise.then( - resolvedFiles => { - resolvedFiles.forEach(file => { - let translatedFile = createI18nFile(file.originalFilePath, file.messages); - stream.queue(translatedFile); - }); - } - ); - }, function () { - Promise.all(parsePromises) - .then(() => { this.queue(null); }) - .catch(reason => { throw new Error(reason); }); - }); -} - -function createI18nFile(originalFilePath: string, messages: any): File { - let result = Object.create(null); +function createI18nFile(name: string, messages: any): File { + const result = Object.create(null); result[''] = [ '--------------------------------------------------------------------------------------------', 'Copyright (c) Microsoft Corporation. All rights reserved.', @@ -1137,7 +757,7 @@ function createI18nFile(originalFilePath: string, messages: any): File { '--------------------------------------------------------------------------------------------', 'Do not edit this file. It is machine generated.' ]; - for (let key of Object.keys(messages)) { + for (const key of Object.keys(messages)) { result[key] = messages[key]; } @@ -1146,7 +766,7 @@ function createI18nFile(originalFilePath: string, messages: any): File { content = content.replace(/\n/g, '\r\n'); } return new File({ - path: path.join(originalFilePath + '.i18n.json'), + path: path.join(name + '.i18n.json'), contents: Buffer.from(content, 'utf8') }); } @@ -1154,7 +774,7 @@ function createI18nFile(originalFilePath: string, messages: any): File { interface I18nPack { version: string; contents: { - [path: string]: Map; + [path: string]: Record; }; } @@ -1165,22 +785,31 @@ export interface TranslationPath { resourceName: string; } -export function prepareI18nPackFiles(externalExtensions: Map, resultingTranslationPaths: TranslationPath[], pseudo = false): NodeJS.ReadWriteStream { - let parsePromises: Promise[] = []; - let mainPack: I18nPack = { version: i18nPackVersion, contents: {} }; - let extensionsPacks: Map = {}; - let errors: any[] = []; +function getRecordFromL10nJsonFormat(l10nJsonFormat: l10nJsonFormat): Record { + const record: Record = {}; + for (const key of Object.keys(l10nJsonFormat)) { + const value = l10nJsonFormat[key]; + record[key] = typeof value === 'string' ? value : value.message; + } + return record; +} + +export function prepareI18nPackFiles(resultingTranslationPaths: TranslationPath[]): NodeJS.ReadWriteStream { + const parsePromises: Promise[] = []; + const mainPack: I18nPack = { version: i18nPackVersion, contents: {} }; + const extensionsPacks: Record = {}; + const errors: any[] = []; return through(function (this: ThroughStream, xlf: File) { - let project = path.basename(path.dirname(path.dirname(xlf.relative))); - let resource = path.basename(xlf.relative, '.xlf'); - let contents = xlf.contents.toString(); + const project = path.basename(path.dirname(path.dirname(xlf.relative))); + const resource = path.basename(xlf.relative, '.xlf'); + const contents = xlf.contents.toString(); log(`Found ${project}: ${resource}`); - let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); + const parsePromise = getL10nFilesFromXlf(contents); parsePromises.push(parsePromise); parsePromise.then( resolvedFiles => { resolvedFiles.forEach(file => { - const path = file.originalFilePath; + const path = file.name; const firstSlash = path.indexOf('/'); if (project === extensionsProject) { @@ -1188,15 +817,15 @@ export function prepareI18nPackFiles(externalExtensions: Map, resultingT if (!extPack) { extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} }; } - const externalId = externalExtensions[resource]; + const externalId = externalExtensionsWithTranslations[resource]; if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent const secondSlash = path.indexOf('/', firstSlash + 1); - extPack.contents[path.substr(secondSlash + 1)] = file.messages; + extPack.contents[path.substring(secondSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); } else { - extPack.contents[path] = file.messages; + extPack.contents[path] = getRecordFromL10nJsonFormat(file.messages); } } else { - mainPack.contents[path.substr(firstSlash + 1)] = file.messages; + mainPack.contents[path.substring(firstSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); } }); } @@ -1213,11 +842,11 @@ export function prepareI18nPackFiles(externalExtensions: Map, resultingT resultingTranslationPaths.push({ id: 'vscode', resourceName: 'main.i18n.json' }); this.queue(translatedMainFile); - for (let extension in extensionsPacks) { + for (const extension in extensionsPacks) { const translatedExtFile = createI18nFile(`extensions/${extension}`, extensionsPacks[extension]); this.queue(translatedExtFile); - const externalExtensionId = externalExtensions[extension]; + const externalExtensionId = externalExtensionsWithTranslations[extension]; if (externalExtensionId) { resultingTranslationPaths.push({ id: externalExtensionId, resourceName: `extensions/${extension}.i18n.json` }); } else { @@ -1234,16 +863,16 @@ export function prepareI18nPackFiles(externalExtensions: Map, resultingT } export function prepareIslFiles(language: Language, innoSetupConfig: InnoSetup): ThroughStream { - let parsePromises: Promise[] = []; + const parsePromises: Promise[] = []; return through(function (this: ThroughStream, xlf: File) { - let stream = this; - let parsePromise = XLF.parse(xlf.contents.toString()); + const stream = this; + const parsePromise = XLF.parse(xlf.contents.toString()); parsePromises.push(parsePromise); parsePromise.then( resolvedFiles => { resolvedFiles.forEach(file => { - let translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); + const translatedFile = createIslFile(file.name, file.messages, language, innoSetupConfig); stream.queue(translatedFile); }); } @@ -1259,25 +888,25 @@ export function prepareIslFiles(language: Language, innoSetupConfig: InnoSetup): }); } -function createIslFile(originalFilePath: string, messages: Map, language: Language, innoSetup: InnoSetup): File { - let content: string[] = []; +function createIslFile(name: string, messages: l10nJsonFormat, language: Language, innoSetup: InnoSetup): File { + const content: string[] = []; let originalContent: TextModel; - if (path.basename(originalFilePath) === 'Default') { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.isl', 'utf8')); + if (path.basename(name) === 'Default') { + originalContent = new TextModel(fs.readFileSync(name + '.isl', 'utf8')); } else { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.en.isl', 'utf8')); + originalContent = new TextModel(fs.readFileSync(name + '.en.isl', 'utf8')); } originalContent.lines.forEach(line => { if (line.length > 0) { - let firstChar = line.charAt(0); + const firstChar = line.charAt(0); if (firstChar === '[' || firstChar === ';') { content.push(line); } else { - let sections: string[] = line.split('='); - let key = sections[0]; + const sections: string[] = line.split('='); + const key = sections[0]; let translated = line; if (key) { - let translatedMessage = messages[key]; + const translatedMessage = messages[key]; if (translatedMessage) { translated = `${key}=${translatedMessage}`; } @@ -1288,7 +917,7 @@ function createIslFile(originalFilePath: string, messages: Map, language } }); - const basename = path.basename(originalFilePath); + const basename = path.basename(name); const filePath = `${basename}.${language.id}.isl`; const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage); @@ -1299,9 +928,9 @@ function createIslFile(originalFilePath: string, messages: Map, language } function encodeEntities(value: string): string { - let result: string[] = []; + const result: string[] = []; for (let i = 0; i < value.length; i++) { - let ch = value[i]; + const ch = value[i]; switch (ch) { case '<': result.push('<'); @@ -1322,7 +951,3 @@ function encodeEntities(value: string): string { function decodeEntities(value: string): string { return value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); } - -function pseudify(message: string) { - return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; -} diff --git a/build/lib/layersChecker.js b/build/lib/layersChecker.js index c83d6fcf984..e766756d9f3 100644 --- a/build/lib/layersChecker.js +++ b/build/lib/layersChecker.js @@ -51,11 +51,13 @@ const CORE_TYPES = [ 'BigInt64Array', 'btoa', 'atob', + 'AbortController', 'AbortSignal', 'MessageChannel', 'MessagePort', 'URL', - 'URLSearchParams' + 'URLSearchParams', + 'ReadonlyArray', ]; // Types that are defined in a common layer but are known to be only // available in native environments should not be allowed in browser @@ -72,6 +74,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 +230,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 +254,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..44490b6f1f9 100644 --- a/build/lib/layersChecker.ts +++ b/build/lib/layersChecker.ts @@ -52,11 +52,13 @@ const CORE_TYPES = [ 'BigInt64Array', 'btoa', 'atob', + 'AbortController', 'AbortSignal', 'MessageChannel', 'MessagePort', 'URL', - 'URLSearchParams' + 'URLSearchParams', + 'ReadonlyArray', ]; // Types that are defined in a common layer but are known to be only @@ -77,6 +79,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 +270,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 +297,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/monaco-api.js b/build/lib/monaco-api.js index d708d6346b3..a7542b711df 100644 --- a/build/lib/monaco-api.js +++ b/build/lib/monaco-api.js @@ -27,7 +27,7 @@ function isDeclaration(ts, a) { } function visitTopLevelDeclarations(ts, sourceFile, visitor) { let stop = false; - let visit = (node) => { + const visit = (node) => { if (stop) { return; } @@ -49,19 +49,19 @@ function visitTopLevelDeclarations(ts, sourceFile, visitor) { visit(sourceFile); } function getAllTopLevelDeclarations(ts, sourceFile) { - let all = []; + const all = []; visitTopLevelDeclarations(ts, sourceFile, (node) => { if (node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.ClassDeclaration || node.kind === ts.SyntaxKind.ModuleDeclaration) { - let interfaceDeclaration = node; - let triviaStart = interfaceDeclaration.pos; - let triviaEnd = interfaceDeclaration.name.pos; - let triviaText = getNodeText(sourceFile, { pos: triviaStart, end: triviaEnd }); + const interfaceDeclaration = node; + const triviaStart = interfaceDeclaration.pos; + const triviaEnd = interfaceDeclaration.name.pos; + const triviaText = getNodeText(sourceFile, { pos: triviaStart, end: triviaEnd }); if (triviaText.indexOf('@internal') === -1) { all.push(node); } } else { - let nodeText = getNodeText(sourceFile, node); + const nodeText = getNodeText(sourceFile, node); if (nodeText.indexOf('@internal') === -1) { all.push(node); } @@ -95,7 +95,7 @@ function getNodeText(sourceFile, node) { function hasModifier(modifiers, kind) { if (modifiers) { for (let i = 0; i < modifiers.length; i++) { - let mod = modifiers[i]; + const mod = modifiers[i]; if (mod.kind === kind) { return true; } @@ -113,14 +113,14 @@ function isDefaultExport(ts, declaration) { function getMassagedTopLevelDeclarationText(ts, sourceFile, declaration, importName, usage, enums) { let result = getNodeText(sourceFile, declaration); if (declaration.kind === ts.SyntaxKind.InterfaceDeclaration || declaration.kind === ts.SyntaxKind.ClassDeclaration) { - let interfaceDeclaration = declaration; + const interfaceDeclaration = declaration; const staticTypeName = (isDefaultExport(ts, interfaceDeclaration) ? `${importName}.default` : `${importName}.${declaration.name.text}`); let instanceTypeName = staticTypeName; const typeParametersCnt = (interfaceDeclaration.typeParameters ? interfaceDeclaration.typeParameters.length : 0); if (typeParametersCnt > 0) { - let arr = []; + const arr = []; for (let i = 0; i < typeParametersCnt; i++) { arr.push('any'); } @@ -129,7 +129,7 @@ function getMassagedTopLevelDeclarationText(ts, sourceFile, declaration, importN const members = interfaceDeclaration.members; members.forEach((member) => { try { - let memberText = getNodeText(sourceFile, member); + const memberText = getNodeText(sourceFile, member); if (memberText.indexOf('@internal') >= 0 || memberText.indexOf('private') >= 0) { result = result.replace(memberText, ''); } @@ -152,7 +152,7 @@ function getMassagedTopLevelDeclarationText(ts, sourceFile, declaration, importN result = result.replace(/export default /g, 'export '); result = result.replace(/export declare /g, 'export '); result = result.replace(/declare /g, ''); - let lines = result.split(/\r\n|\r|\n/); + const lines = result.split(/\r\n|\r|\n/); for (let i = 0; i < lines.length; i++) { if (/\s*\*/.test(lines[i])) { // very likely a comment @@ -177,9 +177,9 @@ function format(ts, text, endl) { return text; } // Parse the source text - let sourceFile = ts.createSourceFile('file.ts', text, ts.ScriptTarget.Latest, /*setParentPointers*/ true); + const sourceFile = ts.createSourceFile('file.ts', text, ts.ScriptTarget.Latest, /*setParentPointers*/ true); // Get the formatting edits on the input sources - let edits = ts.formatting.formatDocument(sourceFile, getRuleProvider(tsfmt), tsfmt); + const edits = ts.formatting.formatDocument(sourceFile, getRuleProvider(tsfmt), tsfmt); // Apply the edits on the input code return applyEdits(text, edits); function countParensCurly(text) { @@ -202,7 +202,7 @@ function format(ts, text, endl) { return r; } function preformat(text, endl) { - let lines = text.split(endl); + const lines = text.split(endl); let inComment = false; let inCommentDeltaIndent = 0; let indent = 0; @@ -282,9 +282,9 @@ function format(ts, text, endl) { // Apply edits in reverse on the existing text let result = text; for (let i = edits.length - 1; i >= 0; i--) { - let change = edits[i]; - let head = result.slice(0, change.span.start); - let tail = result.slice(change.span.start + change.span.length); + const change = edits[i]; + const head = result.slice(0, change.span.start); + const tail = result.slice(change.span.start + change.span.length); result = head + change.newText + tail; } return result; @@ -300,15 +300,15 @@ function createReplacerFromDirectives(directives) { } function createReplacer(data) { data = data || ''; - let rawDirectives = data.split(';'); - let directives = []; + const rawDirectives = data.split(';'); + const directives = []; rawDirectives.forEach((rawDirective) => { if (rawDirective.length === 0) { return; } - let pieces = rawDirective.split('=>'); + const pieces = rawDirective.split('=>'); let findStr = pieces[0]; - let replaceStr = pieces[1]; + const replaceStr = pieces[1]; findStr = findStr.replace(/[\-\\\{\}\*\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&'); findStr = '\\b' + findStr + '\\b'; directives.push([new RegExp(findStr, 'g'), replaceStr]); @@ -317,32 +317,32 @@ function createReplacer(data) { } function generateDeclarationFile(ts, recipe, sourceFileGetter) { const endl = /\r\n/.test(recipe) ? '\r\n' : '\n'; - let lines = recipe.split(endl); - let result = []; + const lines = recipe.split(endl); + const result = []; let usageCounter = 0; - let usageImports = []; - let usage = []; + const usageImports = []; + const usage = []; let failed = false; usage.push(`var a: any;`); usage.push(`var b: any;`); const generateUsageImport = (moduleId) => { - let importName = 'm' + (++usageCounter); + const importName = 'm' + (++usageCounter); usageImports.push(`import * as ${importName} from './${moduleId.replace(/\.d\.ts$/, '')}';`); return importName; }; - let enums = []; + const enums = []; let version = null; lines.forEach(line => { if (failed) { return; } - let m0 = line.match(/^\/\/dtsv=(\d+)$/); + const m0 = line.match(/^\/\/dtsv=(\d+)$/); if (m0) { version = m0[1]; } - let m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/); + const m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/); if (m1) { - let moduleId = m1[1]; + const moduleId = m1[1]; const sourceFile = sourceFileGetter(moduleId); if (!sourceFile) { logErr(`While handling ${line}`); @@ -351,14 +351,14 @@ function generateDeclarationFile(ts, recipe, sourceFileGetter) { return; } const importName = generateUsageImport(moduleId); - let replacer = createReplacer(m1[2]); - let typeNames = m1[3].split(/,/); + const replacer = createReplacer(m1[2]); + const typeNames = m1[3].split(/,/); typeNames.forEach((typeName) => { typeName = typeName.trim(); if (typeName.length === 0) { return; } - let declaration = getTopLevelDeclaration(ts, sourceFile, typeName); + const declaration = getTopLevelDeclaration(ts, sourceFile, typeName); if (!declaration) { logErr(`While handling ${line}`); logErr(`Cannot find ${typeName}`); @@ -369,9 +369,9 @@ function generateDeclarationFile(ts, recipe, sourceFileGetter) { }); return; } - let m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/); + const m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/); if (m2) { - let moduleId = m2[1]; + const moduleId = m2[1]; const sourceFile = sourceFileGetter(moduleId); if (!sourceFile) { logErr(`While handling ${line}`); @@ -380,10 +380,10 @@ function generateDeclarationFile(ts, recipe, sourceFileGetter) { return; } const importName = generateUsageImport(moduleId); - let replacer = createReplacer(m2[2]); - let typeNames = m2[3].split(/,/); - let typesToExcludeMap = {}; - let typesToExcludeArr = []; + const replacer = createReplacer(m2[2]); + const typeNames = m2[3].split(/,/); + const typesToExcludeMap = {}; + const typesToExcludeArr = []; typeNames.forEach((typeName) => { typeName = typeName.trim(); if (typeName.length === 0) { @@ -400,7 +400,7 @@ function generateDeclarationFile(ts, recipe, sourceFileGetter) { } else { // node is ts.VariableStatement - let nodeText = getNodeText(sourceFile, declaration); + const nodeText = getNodeText(sourceFile, declaration); for (let i = 0; i < typesToExcludeArr.length; i++) { if (nodeText.indexOf(typesToExcludeArr[i]) >= 0) { return; @@ -605,7 +605,7 @@ class TypeScriptLanguageServiceHost { } } function execute() { - let r = run3(new DeclarationResolver(new FSProvider())); + const r = run3(new DeclarationResolver(new FSProvider())); if (!r) { throw new Error(`monaco.d.ts generation error - Cannot continue`); } diff --git a/build/lib/monaco-api.ts b/build/lib/monaco-api.ts index e6a06d21ea2..3da550fb277 100644 --- a/build/lib/monaco-api.ts +++ b/build/lib/monaco-api.ts @@ -40,7 +40,7 @@ function isDeclaration(ts: typeof import('typescript'), a: TSTopLevelDeclare): a function visitTopLevelDeclarations(ts: typeof import('typescript'), sourceFile: ts.SourceFile, visitor: (node: TSTopLevelDeclare) => boolean): void { let stop = false; - let visit = (node: ts.Node): void => { + const visit = (node: ts.Node): void => { if (stop) { return; } @@ -67,19 +67,19 @@ function visitTopLevelDeclarations(ts: typeof import('typescript'), sourceFile: function getAllTopLevelDeclarations(ts: typeof import('typescript'), sourceFile: ts.SourceFile): TSTopLevelDeclare[] { - let all: TSTopLevelDeclare[] = []; + const all: TSTopLevelDeclare[] = []; visitTopLevelDeclarations(ts, sourceFile, (node) => { if (node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.ClassDeclaration || node.kind === ts.SyntaxKind.ModuleDeclaration) { - let interfaceDeclaration = node; - let triviaStart = interfaceDeclaration.pos; - let triviaEnd = interfaceDeclaration.name.pos; - let triviaText = getNodeText(sourceFile, { pos: triviaStart, end: triviaEnd }); + const interfaceDeclaration = node; + const triviaStart = interfaceDeclaration.pos; + const triviaEnd = interfaceDeclaration.name.pos; + const triviaText = getNodeText(sourceFile, { pos: triviaStart, end: triviaEnd }); if (triviaText.indexOf('@internal') === -1) { all.push(node); } } else { - let nodeText = getNodeText(sourceFile, node); + const nodeText = getNodeText(sourceFile, node); if (nodeText.indexOf('@internal') === -1) { all.push(node); } @@ -115,10 +115,10 @@ function getNodeText(sourceFile: ts.SourceFile, node: { pos: number; end: number return sourceFile.getFullText().substring(node.pos, node.end); } -function hasModifier(modifiers: ts.NodeArray | undefined, kind: ts.SyntaxKind): boolean { +function hasModifier(modifiers: ts.NodeArray | undefined, kind: ts.SyntaxKind): boolean { if (modifiers) { for (let i = 0; i < modifiers.length; i++) { - let mod = modifiers[i]; + const mod = modifiers[i]; if (mod.kind === kind) { return true; } @@ -141,7 +141,7 @@ function isDefaultExport(ts: typeof import('typescript'), declaration: ts.Interf function getMassagedTopLevelDeclarationText(ts: typeof import('typescript'), sourceFile: ts.SourceFile, declaration: TSTopLevelDeclare, importName: string, usage: string[], enums: IEnumEntry[]): string { let result = getNodeText(sourceFile, declaration); if (declaration.kind === ts.SyntaxKind.InterfaceDeclaration || declaration.kind === ts.SyntaxKind.ClassDeclaration) { - let interfaceDeclaration = declaration; + const interfaceDeclaration = declaration; const staticTypeName = ( isDefaultExport(ts, interfaceDeclaration) @@ -152,7 +152,7 @@ function getMassagedTopLevelDeclarationText(ts: typeof import('typescript'), sou let instanceTypeName = staticTypeName; const typeParametersCnt = (interfaceDeclaration.typeParameters ? interfaceDeclaration.typeParameters.length : 0); if (typeParametersCnt > 0) { - let arr: string[] = []; + const arr: string[] = []; for (let i = 0; i < typeParametersCnt; i++) { arr.push('any'); } @@ -162,7 +162,7 @@ function getMassagedTopLevelDeclarationText(ts: typeof import('typescript'), sou const members: ts.NodeArray = interfaceDeclaration.members; members.forEach((member) => { try { - let memberText = getNodeText(sourceFile, member); + const memberText = getNodeText(sourceFile, member); if (memberText.indexOf('@internal') >= 0 || memberText.indexOf('private') >= 0) { result = result.replace(memberText, ''); } else { @@ -182,7 +182,7 @@ function getMassagedTopLevelDeclarationText(ts: typeof import('typescript'), sou result = result.replace(/export default /g, 'export '); result = result.replace(/export declare /g, 'export '); result = result.replace(/declare /g, ''); - let lines = result.split(/\r\n|\r|\n/); + const lines = result.split(/\r\n|\r|\n/); for (let i = 0; i < lines.length; i++) { if (/\s*\*/.test(lines[i])) { // very likely a comment @@ -212,10 +212,10 @@ function format(ts: typeof import('typescript'), text: string, endl: string): st } // Parse the source text - let sourceFile = ts.createSourceFile('file.ts', text, ts.ScriptTarget.Latest, /*setParentPointers*/ true); + const sourceFile = ts.createSourceFile('file.ts', text, ts.ScriptTarget.Latest, /*setParentPointers*/ true); // Get the formatting edits on the input sources - let edits = (ts).formatting.formatDocument(sourceFile, getRuleProvider(tsfmt), tsfmt); + const edits = (ts).formatting.formatDocument(sourceFile, getRuleProvider(tsfmt), tsfmt); // Apply the edits on the input code return applyEdits(text, edits); @@ -242,7 +242,7 @@ function format(ts: typeof import('typescript'), text: string, endl: string): st } function preformat(text: string, endl: string): string { - let lines = text.split(endl); + const lines = text.split(endl); let inComment = false; let inCommentDeltaIndent = 0; let indent = 0; @@ -328,9 +328,9 @@ function format(ts: typeof import('typescript'), text: string, endl: string): st // Apply edits in reverse on the existing text let result = text; for (let i = edits.length - 1; i >= 0; i--) { - let change = edits[i]; - let head = result.slice(0, change.span.start); - let tail = result.slice(change.span.start + change.span.length); + const change = edits[i]; + const head = result.slice(0, change.span.start); + const tail = result.slice(change.span.start + change.span.length); result = head + change.newText + tail; } return result; @@ -348,15 +348,15 @@ function createReplacerFromDirectives(directives: [RegExp, string][]): (str: str function createReplacer(data: string): (str: string) => string { data = data || ''; - let rawDirectives = data.split(';'); - let directives: [RegExp, string][] = []; + const rawDirectives = data.split(';'); + const directives: [RegExp, string][] = []; rawDirectives.forEach((rawDirective) => { if (rawDirective.length === 0) { return; } - let pieces = rawDirective.split('=>'); + const pieces = rawDirective.split('=>'); let findStr = pieces[0]; - let replaceStr = pieces[1]; + const replaceStr = pieces[1]; findStr = findStr.replace(/[\-\\\{\}\*\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&'); findStr = '\\b' + findStr + '\\b'; @@ -380,12 +380,12 @@ interface IEnumEntry { function generateDeclarationFile(ts: typeof import('typescript'), recipe: string, sourceFileGetter: SourceFileGetter): ITempResult | null { const endl = /\r\n/.test(recipe) ? '\r\n' : '\n'; - let lines = recipe.split(endl); - let result: string[] = []; + const lines = recipe.split(endl); + const result: string[] = []; let usageCounter = 0; - let usageImports: string[] = []; - let usage: string[] = []; + const usageImports: string[] = []; + const usage: string[] = []; let failed = false; @@ -393,12 +393,12 @@ function generateDeclarationFile(ts: typeof import('typescript'), recipe: string usage.push(`var b: any;`); const generateUsageImport = (moduleId: string) => { - let importName = 'm' + (++usageCounter); + const importName = 'm' + (++usageCounter); usageImports.push(`import * as ${importName} from './${moduleId.replace(/\.d\.ts$/, '')}';`); return importName; }; - let enums: IEnumEntry[] = []; + const enums: IEnumEntry[] = []; let version: string | null = null; lines.forEach(line => { @@ -407,14 +407,14 @@ function generateDeclarationFile(ts: typeof import('typescript'), recipe: string return; } - let m0 = line.match(/^\/\/dtsv=(\d+)$/); + const m0 = line.match(/^\/\/dtsv=(\d+)$/); if (m0) { version = m0[1]; } - let m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/); + const m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/); if (m1) { - let moduleId = m1[1]; + const moduleId = m1[1]; const sourceFile = sourceFileGetter(moduleId); if (!sourceFile) { logErr(`While handling ${line}`); @@ -425,15 +425,15 @@ function generateDeclarationFile(ts: typeof import('typescript'), recipe: string const importName = generateUsageImport(moduleId); - let replacer = createReplacer(m1[2]); + const replacer = createReplacer(m1[2]); - let typeNames = m1[3].split(/,/); + const typeNames = m1[3].split(/,/); typeNames.forEach((typeName) => { typeName = typeName.trim(); if (typeName.length === 0) { return; } - let declaration = getTopLevelDeclaration(ts, sourceFile, typeName); + const declaration = getTopLevelDeclaration(ts, sourceFile, typeName); if (!declaration) { logErr(`While handling ${line}`); logErr(`Cannot find ${typeName}`); @@ -445,9 +445,9 @@ function generateDeclarationFile(ts: typeof import('typescript'), recipe: string return; } - let m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/); + const m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/); if (m2) { - let moduleId = m2[1]; + const moduleId = m2[1]; const sourceFile = sourceFileGetter(moduleId); if (!sourceFile) { logErr(`While handling ${line}`); @@ -458,11 +458,11 @@ function generateDeclarationFile(ts: typeof import('typescript'), recipe: string const importName = generateUsageImport(moduleId); - let replacer = createReplacer(m2[2]); + const replacer = createReplacer(m2[2]); - let typeNames = m2[3].split(/,/); - let typesToExcludeMap: { [typeName: string]: boolean } = {}; - let typesToExcludeArr: string[] = []; + const typeNames = m2[3].split(/,/); + const typesToExcludeMap: { [typeName: string]: boolean } = {}; + const typesToExcludeArr: string[] = []; typeNames.forEach((typeName) => { typeName = typeName.trim(); if (typeName.length === 0) { @@ -479,7 +479,7 @@ function generateDeclarationFile(ts: typeof import('typescript'), recipe: string } } else { // node is ts.VariableStatement - let nodeText = getNodeText(sourceFile, declaration); + const nodeText = getNodeText(sourceFile, declaration); for (let i = 0; i < typesToExcludeArr.length; i++) { if (nodeText.indexOf(typesToExcludeArr[i]) >= 0) { return; @@ -732,7 +732,7 @@ class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost { } export function execute(): IMonacoDeclarationResult { - let r = run3(new DeclarationResolver(new FSProvider())); + const r = run3(new DeclarationResolver(new FSProvider())); if (!r) { throw new Error(`monaco.d.ts generation error - Cannot continue`); } diff --git a/build/lib/optimize.js b/build/lib/optimize.js index d5b957d1195..92e449a0cea 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -1,10 +1,10 @@ +"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.minifyTask = exports.optimizeTask = exports.loaderConfig = void 0; +exports.minifyTask = exports.optimizeTask = exports.optimizeLoaderTask = exports.loaderConfig = void 0; const es = require("event-stream"); const gulp = require("gulp"); const concat = require("gulp-concat"); @@ -35,40 +35,58 @@ function loaderConfig() { } exports.loaderConfig = loaderConfig; const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i; -function loader(src, bundledFileHeader, bundleLoader, externalLoaderInfo) { - let sources = [ - `${src}/vs/loader.js` - ]; - if (bundleLoader) { - sources = sources.concat([ - `${src}/vs/css.js`, - `${src}/vs/nls.js` - ]); - } - let isFirst = true; +function loaderPlugin(src, base, amdModuleId) { return (gulp - .src(sources, { base: `${src}` }) + .src(src, { base }) .pipe(es.through(function (data) { - if (isFirst) { - isFirst = false; - this.emit('data', new VinylFile({ - path: 'fake', - base: '.', - contents: Buffer.from(bundledFileHeader) - })); - this.emit('data', data); + if (amdModuleId) { + let contents = data.contents.toString('utf8'); + contents = contents.replace(/^define\(/m, `define("${amdModuleId}",`); + data.contents = Buffer.from(contents); } - else { - this.emit('data', data); + this.emit('data', data); + }))); +} +function loader(src, bundledFileHeader, bundleLoader, externalLoaderInfo) { + let loaderStream = gulp.src(`${src}/vs/loader.js`, { base: `${src}` }); + if (bundleLoader) { + loaderStream = es.merge(loaderStream, loaderPlugin(`${src}/vs/css.js`, `${src}`, 'vs/css'), loaderPlugin(`${src}/vs/nls.js`, `${src}`, 'vs/nls')); + } + const files = []; + const order = (f) => { + if (f.path.endsWith('loader.js')) { + return 0; } + if (f.path.endsWith('css.js')) { + return 1; + } + if (f.path.endsWith('nls.js')) { + return 2; + } + return 3; + }; + return (loaderStream + .pipe(es.through(function (data) { + files.push(data); }, function () { + files.sort((a, b) => { + return order(a) - order(b); + }); + files.unshift(new VinylFile({ + path: 'fake', + base: '.', + contents: Buffer.from(bundledFileHeader) + })); if (externalLoaderInfo !== undefined) { - this.emit('data', new VinylFile({ + files.push(new VinylFile({ path: 'fake2', base: '.', contents: Buffer.from(`require.config(${JSON.stringify(externalLoaderInfo, undefined, 2)});`) })); } + for (const file of files) { + this.emit('data', file); + } this.emit('end'); })) .pipe(concat('vs/loader.js'))); @@ -117,56 +135,94 @@ const DEFAULT_FILE_HEADER = [ ' * Copyright (C) Microsoft Corporation. All rights reserved.', ' *--------------------------------------------------------*/' ].join('\n'); -function optimizeTask(opts) { +function optimizeAMDTask(opts) { const src = opts.src; const entryPoints = opts.entryPoints; const resources = opts.resources; const loaderConfig = opts.loaderConfig; const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; - const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); - const out = opts.out; const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents); - return function () { - const sourcemaps = require('gulp-sourcemaps'); - const bundlesStream = es.through(); // this stream will contain the bundled files - const resourcesStream = es.through(); // this stream will contain the resources - const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json - bundle.bundle(entryPoints, loaderConfig, function (err, result) { - if (err || !result) { - return bundlesStream.emit('error', JSON.stringify(err)); + const sourcemaps = require('gulp-sourcemaps'); + const bundlesStream = es.through(); // this stream will contain the bundled files + const resourcesStream = es.through(); // this stream will contain the resources + const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json + bundle.bundle(entryPoints, loaderConfig, function (err, result) { + if (err || !result) { + return bundlesStream.emit('error', JSON.stringify(err)); + } + toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream); + // Remove css inlined resources + const filteredResources = resources.slice(); + result.cssInlinedResources.forEach(function (resource) { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log('optimizer', 'excluding inlined: ' + resource); } - toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream); - // Remove css inlined resources - const filteredResources = resources.slice(); - result.cssInlinedResources.forEach(function (resource) { - if (process.env['VSCODE_BUILD_VERBOSE']) { - log('optimizer', 'excluding inlined: ' + resource); - } - filteredResources.push('!' + resource); - }); - gulp.src(filteredResources, { base: `${src}`, allowEmpty: true }).pipe(resourcesStream); - const bundleInfoArray = []; - if (opts.bundleInfo) { - bundleInfoArray.push(new VinylFile({ - path: 'bundleInfo.json', - base: '.', - contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t')) - })); - } - es.readArray(bundleInfoArray).pipe(bundleInfoStream); + filteredResources.push('!' + resource); }); - const result = es.merge(loader(src, bundledFileHeader, bundleLoader, opts.externalLoaderInfo), bundlesStream, resourcesStream, bundleInfoStream); - return result - .pipe(sourcemaps.write('./', { - sourceRoot: undefined, - addComment: true, - includeContent: true - })) - .pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({ - fileHeader: bundledFileHeader, - languages: opts.languages - }) : es.through()) - .pipe(gulp.dest(out)); + gulp.src(filteredResources, { base: `${src}`, allowEmpty: true }).pipe(resourcesStream); + const bundleInfoArray = []; + if (opts.bundleInfo) { + bundleInfoArray.push(new VinylFile({ + path: 'bundleInfo.json', + base: '.', + contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t')) + })); + } + es.readArray(bundleInfoArray).pipe(bundleInfoStream); + }); + const result = es.merge(loader(src, bundledFileHeader, false, opts.externalLoaderInfo), bundlesStream, resourcesStream, bundleInfoStream); + return result + .pipe(sourcemaps.write('./', { + sourceRoot: undefined, + addComment: true, + includeContent: true + })) + .pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({ + fileHeader: bundledFileHeader, + languages: opts.languages + }) : es.through()); +} +function optimizeCommonJSTask(opts) { + const esbuild = require('esbuild'); + const src = opts.src; + const entryPoints = opts.entryPoints; + return gulp.src(entryPoints, { base: `${src}`, allowEmpty: true }) + .pipe(es.map((f, cb) => { + esbuild.build({ + entryPoints: [f.path], + bundle: true, + platform: opts.platform, + write: false, + external: opts.external + }).then(res => { + const jsFile = res.outputFiles[0]; + f.contents = Buffer.from(jsFile.contents); + cb(undefined, f); + }); + })); +} +function optimizeManualTask(options) { + const concatenations = options.map(opt => { + return gulp + .src(opt.src) + .pipe(concat(opt.out)); + }); + return es.merge(...concatenations); +} +function optimizeLoaderTask(src, out, bundleLoader, bundledFileHeader = '', externalLoaderInfo) { + return () => loader(src, bundledFileHeader, bundleLoader, externalLoaderInfo).pipe(gulp.dest(out)); +} +exports.optimizeLoaderTask = optimizeLoaderTask; +function optimizeTask(opts) { + return function () { + const optimizers = [optimizeAMDTask(opts.amd)]; + if (opts.commonJS) { + optimizers.push(optimizeCommonJSTask(opts.commonJS)); + } + if (opts.manual) { + optimizers.push(optimizeManualTask(opts.manual)); + } + return es.merge(...optimizers).pipe(gulp.dest(opts.out)); }; } exports.optimizeTask = optimizeTask; diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index fc2a2f42661..2e3943d79f9 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as es from 'event-stream'; import * as gulp from 'gulp'; import * as concat from 'gulp-concat'; @@ -41,41 +39,68 @@ export function loaderConfig() { const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i; -function loader(src: string, bundledFileHeader: string, bundleLoader: boolean, externalLoaderInfo?: any): NodeJS.ReadWriteStream { - let sources = [ - `${src}/vs/loader.js` - ]; - if (bundleLoader) { - sources = sources.concat([ - `${src}/vs/css.js`, - `${src}/vs/nls.js` - ]); - } - - let isFirst = true; +function loaderPlugin(src: string, base: string, amdModuleId: string | undefined): NodeJS.ReadWriteStream { return ( gulp - .src(sources, { base: `${src}` }) - .pipe(es.through(function (data) { - if (isFirst) { - isFirst = false; - this.emit('data', new VinylFile({ - path: 'fake', - base: '.', - contents: Buffer.from(bundledFileHeader) - })); - this.emit('data', data); - } else { - this.emit('data', data); + .src(src, { base }) + .pipe(es.through(function (data: VinylFile) { + if (amdModuleId) { + let contents = data.contents.toString('utf8'); + contents = contents.replace(/^define\(/m, `define("${amdModuleId}",`); + data.contents = Buffer.from(contents); } + this.emit('data', data); + })) + ); +} + +function loader(src: string, bundledFileHeader: string, bundleLoader: boolean, externalLoaderInfo?: any): NodeJS.ReadWriteStream { + let loaderStream = gulp.src(`${src}/vs/loader.js`, { base: `${src}` }); + if (bundleLoader) { + loaderStream = es.merge( + loaderStream, + loaderPlugin(`${src}/vs/css.js`, `${src}`, 'vs/css'), + loaderPlugin(`${src}/vs/nls.js`, `${src}`, 'vs/nls'), + ); + } + + const files: VinylFile[] = []; + const order = (f: VinylFile) => { + if (f.path.endsWith('loader.js')) { + return 0; + } + if (f.path.endsWith('css.js')) { + return 1; + } + if (f.path.endsWith('nls.js')) { + return 2; + } + return 3; + }; + + return ( + loaderStream + .pipe(es.through(function (data) { + files.push(data); }, function () { + files.sort((a, b) => { + return order(a) - order(b); + }); + files.unshift(new VinylFile({ + path: 'fake', + base: '.', + contents: Buffer.from(bundledFileHeader) + })); if (externalLoaderInfo !== undefined) { - this.emit('data', new VinylFile({ + files.push(new VinylFile({ path: 'fake2', base: '.', contents: Buffer.from(`require.config(${JSON.stringify(externalLoaderInfo, undefined, 2)});`) })); } + for (const file of files) { + this.emit('data', file); + } this.emit('end'); })) .pipe(concat('vs/loader.js')) @@ -128,7 +153,7 @@ function toBundleStream(src: string, bundledFileHeader: string, bundles: bundle. })); } -export interface IOptimizeTaskOpts { +export interface IOptimizeAMDTaskOpts { /** * The folder to read files from. */ @@ -159,11 +184,7 @@ export interface IOptimizeTaskOpts { */ bundleInfo: boolean; /** - * (out folder name) - */ - out: string; - /** - * (out folder name) + * Language configuration. */ languages?: Language[]; /** @@ -180,67 +201,164 @@ const DEFAULT_FILE_HEADER = [ ' *--------------------------------------------------------*/' ].join('\n'); -export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream { +function optimizeAMDTask(opts: IOptimizeAMDTaskOpts): NodeJS.ReadWriteStream { const src = opts.src; const entryPoints = opts.entryPoints; const resources = opts.resources; const loaderConfig = opts.loaderConfig; const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; - const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); - const out = opts.out; const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents); - return function () { - const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps'); + const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps'); - const bundlesStream = es.through(); // this stream will contain the bundled files - const resourcesStream = es.through(); // this stream will contain the resources - const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json + const bundlesStream = es.through(); // this stream will contain the bundled files + const resourcesStream = es.through(); // this stream will contain the resources + const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json - bundle.bundle(entryPoints, loaderConfig, function (err, result) { - if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } + bundle.bundle(entryPoints, loaderConfig, function (err, result) { + if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } - toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream); + toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream); - // Remove css inlined resources - const filteredResources = resources.slice(); - result.cssInlinedResources.forEach(function (resource) { - if (process.env['VSCODE_BUILD_VERBOSE']) { - log('optimizer', 'excluding inlined: ' + resource); - } - filteredResources.push('!' + resource); - }); - gulp.src(filteredResources, { base: `${src}`, allowEmpty: true }).pipe(resourcesStream); - - const bundleInfoArray: VinylFile[] = []; - if (opts.bundleInfo) { - bundleInfoArray.push(new VinylFile({ - path: 'bundleInfo.json', - base: '.', - contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t')) - })); + // Remove css inlined resources + const filteredResources = resources.slice(); + result.cssInlinedResources.forEach(function (resource) { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log('optimizer', 'excluding inlined: ' + resource); } - es.readArray(bundleInfoArray).pipe(bundleInfoStream); + filteredResources.push('!' + resource); }); + gulp.src(filteredResources, { base: `${src}`, allowEmpty: true }).pipe(resourcesStream); - const result = es.merge( - loader(src, bundledFileHeader, bundleLoader, opts.externalLoaderInfo), - bundlesStream, - resourcesStream, - bundleInfoStream - ); + const bundleInfoArray: VinylFile[] = []; + if (opts.bundleInfo) { + bundleInfoArray.push(new VinylFile({ + path: 'bundleInfo.json', + base: '.', + contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t')) + })); + } + es.readArray(bundleInfoArray).pipe(bundleInfoStream); + }); - return result - .pipe(sourcemaps.write('./', { - sourceRoot: undefined, - addComment: true, - includeContent: true - })) - .pipe(opts.languages && opts.languages.length ? processNlsFiles({ - fileHeader: bundledFileHeader, - languages: opts.languages - }) : es.through()) - .pipe(gulp.dest(out)); + const result = es.merge( + loader(src, bundledFileHeader, false, opts.externalLoaderInfo), + bundlesStream, + resourcesStream, + bundleInfoStream + ); + + return result + .pipe(sourcemaps.write('./', { + sourceRoot: undefined, + addComment: true, + includeContent: true + })) + .pipe(opts.languages && opts.languages.length ? processNlsFiles({ + fileHeader: bundledFileHeader, + languages: opts.languages + }) : es.through()); +} + +export interface IOptimizeCommonJSTaskOpts { + /** + * The paths to consider for optimizing. + */ + entryPoints: string[]; + /** + * The folder to read files from. + */ + src: string; + /** + * ESBuild `platform` option: https://esbuild.github.io/api/#platform + */ + platform: 'browser' | 'node' | 'neutral'; + /** + * ESBuild `external` option: https://esbuild.github.io/api/#external + */ + external: string[]; +} + +function optimizeCommonJSTask(opts: IOptimizeCommonJSTaskOpts): NodeJS.ReadWriteStream { + const esbuild = require('esbuild') as typeof import('esbuild'); + + const src = opts.src; + const entryPoints = opts.entryPoints; + + return gulp.src(entryPoints, { base: `${src}`, allowEmpty: true }) + .pipe(es.map((f: any, cb) => { + esbuild.build({ + entryPoints: [f.path], + bundle: true, + platform: opts.platform, + write: false, + external: opts.external + }).then(res => { + const jsFile = res.outputFiles[0]; + f.contents = Buffer.from(jsFile.contents); + + cb(undefined, f); + }); + })); +} + +export interface IOptimizeManualTaskOpts { + /** + * The paths to consider for concatenation. The entries + * will be concatenated in the order they are provided. + */ + src: string[]; + /** + * Destination target to concatenate the entryPoints into. + */ + out: string; +} + +function optimizeManualTask(options: IOptimizeManualTaskOpts[]): NodeJS.ReadWriteStream { + const concatenations = options.map(opt => { + return gulp + .src(opt.src) + .pipe(concat(opt.out)); + }); + + return es.merge(...concatenations); +} + +export function optimizeLoaderTask(src: string, out: string, bundleLoader: boolean, bundledFileHeader = '', externalLoaderInfo?: any): () => NodeJS.ReadWriteStream { + return () => loader(src, bundledFileHeader, bundleLoader, externalLoaderInfo).pipe(gulp.dest(out)); +} + +export interface IOptimizeTaskOpts { + /** + * Destination folder for the optimized files. + */ + out: string; + /** + * Optimize AMD modules (using our AMD loader). + */ + amd: IOptimizeAMDTaskOpts; + /** + * Optimize CommonJS modules (using esbuild). + */ + commonJS?: IOptimizeCommonJSTaskOpts; + /** + * Optimize manually by concatenating files. + */ + manual?: IOptimizeManualTaskOpts[]; +} + +export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream { + return function () { + const optimizers = [optimizeAMDTask(opts.amd)]; + if (opts.commonJS) { + optimizers.push(optimizeCommonJSTask(opts.commonJS)); + } + + if (opts.manual) { + optimizers.push(optimizeManualTask(opts.manual)); + } + + return es.merge(...optimizers).pipe(gulp.dest(opts.out)); }; } diff --git a/build/lib/policies.js b/build/lib/policies.js index 3e2a10df350..37bb8e36d0c 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; } @@ -95,10 +96,6 @@ class BooleanPolicy extends BasePolicy { } } class IntPolicy extends BasePolicy { - constructor(name, category, minimumVersion, description, moduleName, defaultValue) { - super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); - this.defaultValue = defaultValue; - } static from(name, category, minimumVersion, description, moduleName, settingNode) { const type = getStringProperty(settingNode, 'type'); if (type !== 'number') { @@ -110,6 +107,10 @@ class IntPolicy extends BasePolicy { } return new IntPolicy(name, category, minimumVersion, description, moduleName, defaultValue); } + constructor(name, category, minimumVersion, description, moduleName, defaultValue) { + super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); + this.defaultValue = defaultValue; + } renderADMXElements() { return [ `` @@ -139,11 +140,6 @@ class StringPolicy extends BasePolicy { } } class StringEnumPolicy extends BasePolicy { - constructor(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions) { - super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); - this.enum_ = enum_; - this.enumDescriptions = enumDescriptions; - } static from(name, category, minimumVersion, description, moduleName, settingNode) { const type = getStringProperty(settingNode, 'type'); if (type !== 'string') { @@ -165,6 +161,11 @@ class StringEnumPolicy extends BasePolicy { } return new StringEnumPolicy(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions); } + constructor(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions) { + super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); + this.enum_ = enum_; + this.enumDescriptions = enumDescriptions; + } renderADMXElements() { return [ ``, @@ -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/preLaunch.js b/build/lib/preLaunch.js index ba8ba1c0382..7d316f594df 100644 --- a/build/lib/preLaunch.js +++ b/build/lib/preLaunch.js @@ -1,8 +1,8 @@ +"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 }); // @ts-check const path = require("path"); diff --git a/build/lib/preLaunch.ts b/build/lib/preLaunch.ts index 57441870cc4..3d3f513b591 100644 --- a/build/lib/preLaunch.ts +++ b/build/lib/preLaunch.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - // @ts-check import * as path from 'path'; diff --git a/build/lib/reporter.js b/build/lib/reporter.js index def8f24a065..0c735614324 100644 --- a/build/lib/reporter.js +++ b/build/lib/reporter.js @@ -1,8 +1,8 @@ +"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.createReporter = void 0; const es = require("event-stream"); diff --git a/build/lib/reporter.ts b/build/lib/reporter.ts index f875fce908a..a9c8b53671a 100644 --- a/build/lib/reporter.ts +++ b/build/lib/reporter.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as es from 'event-stream'; import * as _ from 'underscore'; import * as fancyLog from 'fancy-log'; diff --git a/build/lib/snapshotLoader.js b/build/lib/snapshotLoader.js index ee626a0f7f1..ef1ecadbb43 100644 --- a/build/lib/snapshotLoader.js +++ b/build/lib/snapshotLoader.js @@ -1,8 +1,8 @@ +"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'; var snaps; (function (snaps) { const fs = require('fs'); diff --git a/build/lib/snapshotLoader.ts b/build/lib/snapshotLoader.ts index 40b06d67d05..c3d66dba7e1 100644 --- a/build/lib/snapshotLoader.ts +++ b/build/lib/snapshotLoader.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - namespace snaps { const fs = require('fs'); diff --git a/build/lib/standalone.js b/build/lib/standalone.js index f2116eb159e..80accea5f4e 100644 --- a/build/lib/standalone.js +++ b/build/lib/standalone.js @@ -10,7 +10,7 @@ const path = require("path"); const tss = require("./treeshaking"); const REPO_ROOT = path.join(__dirname, '../../'); const SRC_DIR = path.join(REPO_ROOT, 'src'); -let dirCache = {}; +const dirCache = {}; function writeFile(filePath, contents) { function ensureDirs(dirPath) { if (dirCache[dirPath]) { @@ -53,13 +53,13 @@ function extractEditor(options) { options.typings.push(`../node_modules/@types/${type}/index.d.ts`); }); } - let result = tss.shake(options); - for (let fileName in result) { + const result = tss.shake(options); + for (const fileName in result) { if (result.hasOwnProperty(fileName)) { writeFile(path.join(options.destRoot, fileName), result[fileName]); } } - let copied = {}; + const copied = {}; const copyFile = (fileName) => { if (copied[fileName]) { return; @@ -72,7 +72,7 @@ function extractEditor(options) { const writeOutputFile = (fileName, contents) => { writeFile(path.join(options.destRoot, fileName), contents); }; - for (let fileName in result) { + for (const fileName in result) { if (result.hasOwnProperty(fileName)) { const fileContents = result[fileName]; const info = ts.preProcessFile(fileContents); @@ -102,13 +102,12 @@ function extractEditor(options) { delete tsConfig.compilerOptions.moduleResolution; writeOutputFile('tsconfig.json', JSON.stringify(tsConfig, null, '\t')); [ - 'vs/css.build.js', - 'vs/css.d.ts', - 'vs/css.js', + 'vs/css.build.ts', + 'vs/css.ts', 'vs/loader.js', - 'vs/nls.build.js', - 'vs/nls.d.ts', - 'vs/nls.js', + 'vs/loader.d.ts', + 'vs/nls.build.ts', + 'vs/nls.ts', 'vs/nls.mock.ts', ].forEach(copyFile); } @@ -119,7 +118,7 @@ function createESMSourcesAndResources2(options) { const OUT_FOLDER = path.join(REPO_ROOT, options.outFolder); const OUT_RESOURCES_FOLDER = path.join(REPO_ROOT, options.outResourcesFolder); const getDestAbsoluteFilePath = (file) => { - let dest = options.renames[file.replace(/\\/g, '/')] || file; + const dest = options.renames[file.replace(/\\/g, '/')] || file; if (dest === 'tsconfig.json') { return path.join(OUT_FOLDER, `tsconfig.json`); } @@ -181,7 +180,7 @@ function createESMSourcesAndResources2(options) { + relativePath + fileContents.substring(end + 1)); } - fileContents = fileContents.replace(/import ([a-zA-z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) { + fileContents = fileContents.replace(/import ([a-zA-Z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) { return `import * as ${m1} from ${m2};`; }); write(getDestAbsoluteFilePath(file), fileContents); @@ -193,7 +192,7 @@ function createESMSourcesAndResources2(options) { if (dir.charAt(dir.length - 1) !== '/' || dir.charAt(dir.length - 1) !== '\\') { dir += '/'; } - let result = []; + const result = []; _walkDirRecursive(dir, result, dir.length); return result; } @@ -215,7 +214,7 @@ function createESMSourcesAndResources2(options) { } writeFile(absoluteFilePath, contents); function toggleComments(fileContents) { - let lines = fileContents.split(/\r\n|\r|\n/); + const lines = fileContents.split(/\r\n|\r|\n/); let mode = 0; for (let i = 0; i < lines.length; i++) { const line = lines[i]; @@ -278,14 +277,14 @@ function transportCSS(module, enqueue, write) { let DATA = ';base64,' + fileContents.toString('base64'); if (!forceBase64 && /\.svg$/.test(url)) { // .svg => url encode as explained at https://codepen.io/tigt/post/optimizing-svgs-in-data-uris - let newText = fileContents.toString() + const newText = fileContents.toString() .replace(/"/g, '\'') .replace(//g, '%3E') .replace(/&/g, '%26') .replace(/#/g, '%23') .replace(/\s+/g, ' '); - let encodedData = ',' + newText; + const encodedData = ',' + newText; if (encodedData.length < DATA.length) { DATA = encodedData; } diff --git a/build/lib/standalone.ts b/build/lib/standalone.ts index 3483de02a39..775a1be5996 100644 --- a/build/lib/standalone.ts +++ b/build/lib/standalone.ts @@ -10,7 +10,7 @@ import * as tss from './treeshaking'; const REPO_ROOT = path.join(__dirname, '../../'); const SRC_DIR = path.join(REPO_ROOT, 'src'); -let dirCache: { [dir: string]: boolean } = {}; +const dirCache: { [dir: string]: boolean } = {}; function writeFile(filePath: string, contents: Buffer | string): void { function ensureDirs(dirPath: string): void { @@ -63,13 +63,13 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str }); } - let result = tss.shake(options); - for (let fileName in result) { + const result = tss.shake(options); + for (const fileName in result) { if (result.hasOwnProperty(fileName)) { writeFile(path.join(options.destRoot, fileName), result[fileName]); } } - let copied: { [fileName: string]: boolean } = {}; + const copied: { [fileName: string]: boolean } = {}; const copyFile = (fileName: string) => { if (copied[fileName]) { return; @@ -82,7 +82,7 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str const writeOutputFile = (fileName: string, contents: string | Buffer) => { writeFile(path.join(options.destRoot, fileName), contents); }; - for (let fileName in result) { + for (const fileName in result) { if (result.hasOwnProperty(fileName)) { const fileContents = result[fileName]; const info = ts.preProcessFile(fileContents); @@ -115,13 +115,12 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str writeOutputFile('tsconfig.json', JSON.stringify(tsConfig, null, '\t')); [ - 'vs/css.build.js', - 'vs/css.d.ts', - 'vs/css.js', + 'vs/css.build.ts', + 'vs/css.ts', 'vs/loader.js', - 'vs/nls.build.js', - 'vs/nls.d.ts', - 'vs/nls.js', + 'vs/loader.d.ts', + 'vs/nls.build.ts', + 'vs/nls.ts', 'vs/nls.mock.ts', ].forEach(copyFile); } @@ -142,7 +141,7 @@ export function createESMSourcesAndResources2(options: IOptions2): void { const OUT_RESOURCES_FOLDER = path.join(REPO_ROOT, options.outResourcesFolder); const getDestAbsoluteFilePath = (file: string): string => { - let dest = options.renames[file.replace(/\\/g, '/')] || file; + const dest = options.renames[file.replace(/\\/g, '/')] || file; if (dest === 'tsconfig.json') { return path.join(OUT_FOLDER, `tsconfig.json`); } @@ -213,7 +212,7 @@ export function createESMSourcesAndResources2(options: IOptions2): void { ); } - fileContents = fileContents.replace(/import ([a-zA-z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) { + fileContents = fileContents.replace(/import ([a-zA-Z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) { return `import * as ${m1} from ${m2};`; }); @@ -229,7 +228,7 @@ export function createESMSourcesAndResources2(options: IOptions2): void { if (dir.charAt(dir.length - 1) !== '/' || dir.charAt(dir.length - 1) !== '\\') { dir += '/'; } - let result: string[] = []; + const result: string[] = []; _walkDirRecursive(dir, result, dir.length); return result; } @@ -253,7 +252,7 @@ export function createESMSourcesAndResources2(options: IOptions2): void { writeFile(absoluteFilePath, contents); function toggleComments(fileContents: string): string { - let lines = fileContents.split(/\r\n|\r|\n/); + const lines = fileContents.split(/\r\n|\r|\n/); let mode = 0; for (let i = 0; i < lines.length; i++) { const line = lines[i]; @@ -325,14 +324,14 @@ function transportCSS(module: string, enqueue: (module: string) => void, write: if (!forceBase64 && /\.svg$/.test(url)) { // .svg => url encode as explained at https://codepen.io/tigt/post/optimizing-svgs-in-data-uris - let newText = fileContents.toString() + const newText = fileContents.toString() .replace(/"/g, '\'') .replace(//g, '%3E') .replace(/&/g, '%26') .replace(/#/g, '%23') .replace(/\s+/g, ' '); - let encodedData = ',' + newText; + const encodedData = ',' + newText; if (encodedData.length < DATA.length) { DATA = encodedData; } diff --git a/build/lib/stats.js b/build/lib/stats.js index 6d705a9a16b..869ac2043b3 100644 --- a/build/lib/stats.js +++ b/build/lib/stats.js @@ -1,8 +1,8 @@ +"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.createStatsStream = void 0; const es = require("event-stream"); diff --git a/build/lib/stats.ts b/build/lib/stats.ts index 6e85cf68e29..fe4b22453b5 100644 --- a/build/lib/stats.ts +++ b/build/lib/stats.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as es from 'event-stream'; import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; diff --git a/build/lib/task.js b/build/lib/task.js index d08ab8acde8..ba4babafc18 100644 --- a/build/lib/task.js +++ b/build/lib/task.js @@ -1,8 +1,8 @@ +"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.define = exports.parallel = exports.series = void 0; const fancyLog = require("fancy-log"); diff --git a/build/lib/task.ts b/build/lib/task.ts index 4e571ec9294..7d2a4dee016 100644 --- a/build/lib/task.ts +++ b/build/lib/task.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; diff --git a/build/lib/test/i18n.test.js b/build/lib/test/i18n.test.js index 4d339c120a9..3f8015e8c90 100644 --- a/build/lib/test/i18n.test.js +++ b/build/lib/test/i18n.test.js @@ -9,20 +9,20 @@ const i18n = require("../i18n"); suite('XLF Parser Tests', () => { const sampleXlf = 'Key #1Key #2 &'; const sampleTranslatedXlf = 'Key #1КĐŊĐžĐŋĐēа #1Key #2 &КĐŊĐžĐŋĐēа #2 &'; - const originalFilePath = 'vs/base/common/keybinding'; + const name = 'vs/base/common/keybinding'; const keys = ['key1', 'key2']; const messages = ['Key #1', 'Key #2 &']; const translatedMessages = { key1: 'КĐŊĐžĐŋĐēа #1', key2: 'КĐŊĐžĐŋĐēа #2 &' }; test('Keys & messages to XLF conversion', () => { const xlf = new i18n.XLF('vscode-workbench'); - xlf.addFile(originalFilePath, keys, messages); + xlf.addFile(name, keys, messages); const xlfString = xlf.toString(); assert.strictEqual(xlfString.replace(/\s{2,}/g, ''), sampleXlf); }); test('XLF to keys & messages conversion', () => { i18n.XLF.parse(sampleTranslatedXlf).then(function (resolvedFiles) { assert.deepStrictEqual(resolvedFiles[0].messages, translatedMessages); - assert.strictEqual(resolvedFiles[0].originalFilePath, originalFilePath); + assert.strictEqual(resolvedFiles[0].name, name); }); }); test('JSON file source path to Transifex resource match', () => { diff --git a/build/lib/test/i18n.test.ts b/build/lib/test/i18n.test.ts index ab0924c4350..b8a68323dd7 100644 --- a/build/lib/test/i18n.test.ts +++ b/build/lib/test/i18n.test.ts @@ -9,14 +9,14 @@ import i18n = require('../i18n'); suite('XLF Parser Tests', () => { const sampleXlf = 'Key #1Key #2 &'; const sampleTranslatedXlf = 'Key #1КĐŊĐžĐŋĐēа #1Key #2 &КĐŊĐžĐŋĐēа #2 &'; - const originalFilePath = 'vs/base/common/keybinding'; + const name = 'vs/base/common/keybinding'; const keys = ['key1', 'key2']; const messages = ['Key #1', 'Key #2 &']; const translatedMessages = { key1: 'КĐŊĐžĐŋĐēа #1', key2: 'КĐŊĐžĐŋĐēа #2 &' }; test('Keys & messages to XLF conversion', () => { const xlf = new i18n.XLF('vscode-workbench'); - xlf.addFile(originalFilePath, keys, messages); + xlf.addFile(name, keys, messages); const xlfString = xlf.toString(); assert.strictEqual(xlfString.replace(/\s{2,}/g, ''), sampleXlf); @@ -25,7 +25,7 @@ suite('XLF Parser Tests', () => { test('XLF to keys & messages conversion', () => { i18n.XLF.parse(sampleTranslatedXlf).then(function (resolvedFiles) { assert.deepStrictEqual(resolvedFiles[0].messages, translatedMessages); - assert.strictEqual(resolvedFiles[0].originalFilePath, originalFilePath); + assert.strictEqual(resolvedFiles[0].name, name); }); }); diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index 008eb27aca2..029235f7709 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -1,8 +1,8 @@ +"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.shake = exports.toStringShakeLevel = exports.ShakeLevel = void 0; const fs = require("fs"); @@ -32,7 +32,7 @@ function printDiagnostics(options, diagnostics) { result += `${path.join(options.sourcesRoot, diag.file.fileName)}`; } if (diag.file && diag.start) { - let location = diag.file.getLineAndCharacterOfPosition(diag.start); + const location = diag.file.getLineAndCharacterOfPosition(diag.start); result += `:${location.line + 1}:${location.character}`; } result += ` - ` + JSON.stringify(diag.messageText); @@ -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; } @@ -150,7 +152,7 @@ function processLibFiles(ts, options) { result[key] = sourceText; // precess dependencies and "recurse" const info = ts.preProcessFile(sourceText); - for (let ref of info.libReferenceDirectives) { + for (const ref of info.libReferenceDirectives) { stack.push(ref.fileName); } } @@ -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) { @@ -467,50 +490,56 @@ function markNodes(ts, languageService, options) { } const nodeSourceFile = node.getSourceFile(); const loop = (node) => { - const [symbol, symbolImportNode] = getRealNodeSymbol(ts, checker, node); - if (symbolImportNode) { - setColor(symbolImportNode, 2 /* NodeColor.Black */); - } - if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { - for (let i = 0, len = symbol.declarations.length; i < len; i++) { - const declaration = symbol.declarations[i]; - if (ts.isSourceFile(declaration)) { - // Do not enqueue full source files - // (they can be the declaration of a module import) - continue; + const symbols = getRealNodeSymbol(ts, checker, node); + for (const { symbol, symbolImportNode } of symbols) { + if (symbolImportNode) { + setColor(symbolImportNode, 2 /* NodeColor.Black */); + const importDeclarationNode = findParentImportDeclaration(symbolImportNode); + if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) { + enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text); } - if (options.shakeLevel === 2 /* ShakeLevel.ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { - enqueue_black(declaration.name); - for (let j = 0; j < declaration.members.length; j++) { - const member = declaration.members[j]; - const memberName = member.name ? member.name.getText() : null; - if (ts.isConstructorDeclaration(member) - || ts.isConstructSignatureDeclaration(member) - || ts.isIndexSignatureDeclaration(member) - || ts.isCallSignatureDeclaration(member) - || memberName === '[Symbol.iterator]' - || memberName === '[Symbol.toStringTag]' - || memberName === 'toJSON' - || memberName === 'toString' - || memberName === 'dispose' // TODO: keeping all `dispose` methods - || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... - ) { - enqueue_black(member); + } + if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { + for (let i = 0, len = symbol.declarations.length; i < len; i++) { + const declaration = symbol.declarations[i]; + if (ts.isSourceFile(declaration)) { + // Do not enqueue full source files + // (they can be the declaration of a module import) + continue; + } + if (options.shakeLevel === 2 /* ShakeLevel.ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { + enqueue_black(declaration.name); + for (let j = 0; j < declaration.members.length; j++) { + const member = declaration.members[j]; + const memberName = member.name ? member.name.getText() : null; + if (ts.isConstructorDeclaration(member) + || ts.isConstructSignatureDeclaration(member) + || ts.isIndexSignatureDeclaration(member) + || ts.isCallSignatureDeclaration(member) + || memberName === '[Symbol.iterator]' + || memberName === '[Symbol.toStringTag]' + || memberName === 'toJSON' + || memberName === 'toString' + || memberName === 'dispose' // TODO: keeping all `dispose` methods + || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... + ) { + enqueue_black(member); + } + if (isStaticMemberWithSideEffects(ts, member)) { + enqueue_black(member); + } } - if (isStaticMemberWithSideEffects(ts, member)) { - enqueue_black(member); + // queue the heritage clauses + if (declaration.heritageClauses) { + for (const heritageClause of declaration.heritageClauses) { + enqueue_black(heritageClause); + } } } - // queue the heritage clauses - if (declaration.heritageClauses) { - for (let heritageClause of declaration.heritageClauses) { - enqueue_black(heritageClause); - } + else { + enqueue_black(declaration); } } - else { - enqueue_black(declaration); - } } } node.forEachChild(loop); @@ -551,7 +580,7 @@ function generateResult(ts, languageService, shakeLevel) { if (!program) { throw new Error('Could not get program from language service'); } - let result = {}; + const result = {}; const writeFile = (filePath, contents) => { result[filePath] = contents; }; @@ -567,7 +596,7 @@ function generateResult(ts, languageService, shakeLevel) { } return; } - let text = sourceFile.text; + const text = sourceFile.text; let result = ''; function keep(node) { result += text.substring(node.pos, node.end); @@ -597,7 +626,7 @@ function generateResult(ts, languageService, shakeLevel) { } } else { - let survivingImports = []; + const survivingImports = []; for (const importNode of node.importClause.namedBindings.elements) { if (getColor(importNode) === 2 /* NodeColor.Black */) { survivingImports.push(importNode.getFullText(sourceFile)); @@ -626,7 +655,7 @@ function generateResult(ts, languageService, shakeLevel) { } if (ts.isExportDeclaration(node)) { if (node.exportClause && node.moduleSpecifier && ts.isNamedExports(node.exportClause)) { - let survivingExports = []; + const survivingExports = []; for (const exportSpecifier of node.exportClause.elements) { if (getColor(exportSpecifier) === 2 /* NodeColor.Black */) { survivingExports.push(exportSpecifier.getFullText(sourceFile)); @@ -647,8 +676,8 @@ function generateResult(ts, languageService, shakeLevel) { // keep method continue; } - let pos = member.pos - node.pos; - let end = member.end - node.pos; + const pos = member.pos - node.pos; + const end = member.end - node.pos; toWrite = toWrite.substring(0, pos) + toWrite.substring(end); } return write(toWrite); @@ -661,11 +690,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; @@ -697,13 +738,20 @@ function findSymbolFromHeritageType(ts, checker, type) { return findSymbolFromHeritageType(ts, checker, type.expression); } if (ts.isIdentifier(type)) { - return getRealNodeSymbol(ts, checker, type)[0]; + const tmp = getRealNodeSymbol(ts, checker, type); + return (tmp.length > 0 ? tmp[0].symbol : null); } if (ts.isPropertyAccessExpression(type)) { return findSymbolFromHeritageType(ts, checker, type.name); } return null; } +class SymbolImportTuple { + constructor(symbol, symbolImportNode) { + this.symbol = symbol; + this.symbolImportNode = symbolImportNode; + } +} /** * Returns the node's symbol and the `import` node (if the symbol resolved from a different module) */ @@ -735,7 +783,7 @@ function getRealNodeSymbol(ts, checker, node) { } if (!ts.isShorthandPropertyAssignment(node)) { if (node.getChildCount() !== 0) { - return [null, null]; + return []; } } const { parent } = node; @@ -781,10 +829,7 @@ function getRealNodeSymbol(ts, checker, node) { const type = checker.getTypeAtLocation(parent.parent); if (name && type) { if (type.isUnion()) { - const prop = type.types[0].getProperty(name); - if (prop) { - symbol = prop; - } + return generateMultipleSymbols(type, name, importNode); } else { const prop = type.getProperty(name); @@ -815,9 +860,19 @@ function getRealNodeSymbol(ts, checker, node) { } } if (symbol && symbol.declarations) { - return [symbol, importNode]; + return [new SymbolImportTuple(symbol, importNode)]; + } + return []; + function generateMultipleSymbols(type, name, importNode) { + const result = []; + for (const t of type.types) { + const prop = t.getProperty(name); + if (prop && prop.declarations) { + result.push(new SymbolImportTuple(prop, importNode)); + } + } + return result; } - return [null, null]; } /** Get the token whose text contains the position */ function getTokenAtPosition(ts, sourceFile, position, allowPositionInLeadingTrivia, includeEndPosition) { @@ -839,3 +894,4 @@ function getTokenAtPosition(ts, sourceFile, position, allowPositionInLeadingTriv return current; } } +//#endregion diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index 113340285a8..020e567eb72 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as fs from 'fs'; import * as path from 'path'; import type * as ts from 'typescript'; @@ -73,7 +71,7 @@ function printDiagnostics(options: ITreeShakingOptions, diagnostics: ReadonlyArr result += `${path.join(options.sourcesRoot, diag.file.fileName)}`; } if (diag.file && diag.start) { - let location = diag.file.getLineAndCharacterOfPosition(diag.start); + const location = diag.file.getLineAndCharacterOfPosition(diag.start); result += `:${location.line + 1}:${location.character}`; } result += ` - ` + JSON.stringify(diag.messageText); @@ -144,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; } @@ -216,7 +216,7 @@ function processLibFiles(ts: typeof import('typescript'), options: ITreeShakingO // precess dependencies and "recurse" const info = ts.preProcessFile(sourceText); - for (let ref of info.libReferenceDirectives) { + for (const ref of info.libReferenceDirectives) { stack.push(ref.fileName); } } @@ -307,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); @@ -449,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; @@ -531,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); } @@ -587,54 +609,60 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language const nodeSourceFile = node.getSourceFile(); const loop = (node: ts.Node) => { - const [symbol, symbolImportNode] = getRealNodeSymbol(ts, checker, node); - if (symbolImportNode) { - setColor(symbolImportNode, NodeColor.Black); - } - - if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { - for (let i = 0, len = symbol.declarations.length; i < len; i++) { - const declaration = symbol.declarations[i]; - if (ts.isSourceFile(declaration)) { - // Do not enqueue full source files - // (they can be the declaration of a module import) - continue; + const symbols = getRealNodeSymbol(ts, checker, node); + for (const { symbol, symbolImportNode } of symbols) { + if (symbolImportNode) { + setColor(symbolImportNode, NodeColor.Black); + const importDeclarationNode = findParentImportDeclaration(symbolImportNode); + if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) { + enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text); } + } - if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { - enqueue_black(declaration.name!); - - for (let j = 0; j < declaration.members.length; j++) { - const member = declaration.members[j]; - const memberName = member.name ? member.name.getText() : null; - if ( - ts.isConstructorDeclaration(member) - || ts.isConstructSignatureDeclaration(member) - || ts.isIndexSignatureDeclaration(member) - || ts.isCallSignatureDeclaration(member) - || memberName === '[Symbol.iterator]' - || memberName === '[Symbol.toStringTag]' - || memberName === 'toJSON' - || memberName === 'toString' - || memberName === 'dispose'// TODO: keeping all `dispose` methods - || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... - ) { - enqueue_black(member); - } - - if (isStaticMemberWithSideEffects(ts, member)) { - enqueue_black(member); - } + if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { + for (let i = 0, len = symbol.declarations.length; i < len; i++) { + const declaration = symbol.declarations[i]; + if (ts.isSourceFile(declaration)) { + // Do not enqueue full source files + // (they can be the declaration of a module import) + continue; } - // queue the heritage clauses - if (declaration.heritageClauses) { - for (let heritageClause of declaration.heritageClauses) { - enqueue_black(heritageClause); + if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { + enqueue_black(declaration.name!); + + for (let j = 0; j < declaration.members.length; j++) { + const member = declaration.members[j]; + const memberName = member.name ? member.name.getText() : null; + if ( + ts.isConstructorDeclaration(member) + || ts.isConstructSignatureDeclaration(member) + || ts.isIndexSignatureDeclaration(member) + || ts.isCallSignatureDeclaration(member) + || memberName === '[Symbol.iterator]' + || memberName === '[Symbol.toStringTag]' + || memberName === 'toJSON' + || memberName === 'toString' + || memberName === 'dispose'// TODO: keeping all `dispose` methods + || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... + ) { + enqueue_black(member); + } + + if (isStaticMemberWithSideEffects(ts, member)) { + enqueue_black(member); + } } + + // queue the heritage clauses + if (declaration.heritageClauses) { + for (const heritageClause of declaration.heritageClauses) { + enqueue_black(heritageClause); + } + } + } else { + enqueue_black(declaration); } - } else { - enqueue_black(declaration); } } } @@ -682,7 +710,7 @@ function generateResult(ts: typeof import('typescript'), languageService: ts.Lan throw new Error('Could not get program from language service'); } - let result: ITreeShakingResult = {}; + const result: ITreeShakingResult = {}; const writeFile = (filePath: string, contents: string): void => { result[filePath] = contents; }; @@ -700,7 +728,7 @@ function generateResult(ts: typeof import('typescript'), languageService: ts.Lan return; } - let text = sourceFile.text; + const text = sourceFile.text; let result = ''; function keep(node: ts.Node): void { @@ -734,7 +762,7 @@ function generateResult(ts: typeof import('typescript'), languageService: ts.Lan return keep(node); } } else { - let survivingImports: string[] = []; + const survivingImports: string[] = []; for (const importNode of node.importClause.namedBindings.elements) { if (getColor(importNode) === NodeColor.Black) { survivingImports.push(importNode.getFullText(sourceFile)); @@ -762,7 +790,7 @@ function generateResult(ts: typeof import('typescript'), languageService: ts.Lan if (ts.isExportDeclaration(node)) { if (node.exportClause && node.moduleSpecifier && ts.isNamedExports(node.exportClause)) { - let survivingExports: string[] = []; + const survivingExports: string[] = []; for (const exportSpecifier of node.exportClause.elements) { if (getColor(exportSpecifier) === NodeColor.Black) { survivingExports.push(exportSpecifier.getFullText(sourceFile)); @@ -785,8 +813,8 @@ function generateResult(ts: typeof import('typescript'), languageService: ts.Lan continue; } - let pos = member.pos - node.pos; - let end = member.end - node.pos; + const pos = member.pos - node.pos; + const end = member.end - node.pos; toWrite = toWrite.substring(0, pos) + toWrite.substring(end); } return write(toWrite); @@ -802,11 +830,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; } @@ -843,7 +881,8 @@ function findSymbolFromHeritageType(ts: typeof import('typescript'), checker: ts return findSymbolFromHeritageType(ts, checker, type.expression); } if (ts.isIdentifier(type)) { - return getRealNodeSymbol(ts, checker, type)[0]; + const tmp = getRealNodeSymbol(ts, checker, type); + return (tmp.length > 0 ? tmp[0].symbol : null); } if (ts.isPropertyAccessExpression(type)) { return findSymbolFromHeritageType(ts, checker, type.name); @@ -851,10 +890,17 @@ function findSymbolFromHeritageType(ts: typeof import('typescript'), checker: ts return null; } +class SymbolImportTuple { + constructor( + public readonly symbol: ts.Symbol | null, + public readonly symbolImportNode: ts.Declaration | null + ) { } +} + /** * Returns the node's symbol and the `import` node (if the symbol resolved from a different module) */ -function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChecker, node: ts.Node): [ts.Symbol | null, ts.Declaration | null] { +function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChecker, node: ts.Node): SymbolImportTuple[] { // Use some TypeScript internals to avoid code duplication type ObjectLiteralElementWithName = ts.ObjectLiteralElement & { name: ts.PropertyName; parent: ts.ObjectLiteralExpression | ts.JsxAttributes }; @@ -887,7 +933,7 @@ function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChec if (!ts.isShorthandPropertyAssignment(node)) { if (node.getChildCount() !== 0) { - return [null, null]; + return []; } } @@ -940,10 +986,7 @@ function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChec const type = checker.getTypeAtLocation(parent.parent); if (name && type) { if (type.isUnion()) { - const prop = type.types[0].getProperty(name); - if (prop) { - symbol = prop; - } + return generateMultipleSymbols(type, name, importNode); } else { const prop = type.getProperty(name); if (prop) { @@ -975,10 +1018,21 @@ function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChec } if (symbol && symbol.declarations) { - return [symbol, importNode]; + return [new SymbolImportTuple(symbol, importNode)]; } - return [null, null]; + return []; + + function generateMultipleSymbols(type: ts.UnionType, name: string, importNode: ts.Declaration | null): SymbolImportTuple[] { + const result: SymbolImportTuple[] = []; + for (const t of type.types) { + const prop = t.getProperty(name); + if (prop && prop.declarations) { + result.push(new SymbolImportTuple(prop, importNode)); + } + } + return result; + } } /** Get the token whose text contains the position */ diff --git a/build/lib/tsb/builder.js b/build/lib/tsb/builder.js index cb700a54077..be74a30a17a 100644 --- a/build/lib/tsb/builder.js +++ b/build/lib/tsb/builder.js @@ -9,7 +9,6 @@ const fs_1 = require("fs"); const path = require("path"); const crypto = require("crypto"); const utils = require("./utils"); -const log = require("fancy-log"); const colors = require("ansi-colors"); const ts = require("typescript"); const Vinyl = require("vinyl"); @@ -23,12 +22,15 @@ function normalize(path) { return path.replace(/\\/g, '/'); } function createTypeScriptBuilder(config, projectFile, cmd) { - function _log(topic, message) { - if (config.verbose) { - log(colors.cyan(topic), message); - } - } - let host = new LanguageServiceHost(cmd, projectFile, _log), service = ts.createLanguageService(host, ts.createDocumentRegistry()), lastBuildVersion = Object.create(null), lastDtsHash = Object.create(null), userWantsDeclarations = cmd.options.declaration, oldErrors = Object.create(null), headUsed = process.memoryUsage().heapUsed, emitSourceMapsInStream = true; + const _log = config.logFn; + const host = new LanguageServiceHost(cmd, projectFile, _log); + const service = ts.createLanguageService(host, ts.createDocumentRegistry()); + const lastBuildVersion = Object.create(null); + const lastDtsHash = Object.create(null); + const userWantsDeclarations = cmd.options.declaration; + let oldErrors = Object.create(null); + let headUsed = process.memoryUsage().heapUsed; + let emitSourceMapsInStream = true; // always emit declaraction files host.getCompilationSettings().declaration = true; function file(file) { @@ -85,8 +87,8 @@ function createTypeScriptBuilder(config, projectFile, cmd) { process.nextTick(function () { if (/\.d\.ts$/.test(fileName)) { // if it's already a d.ts file just emit it signature - let snapshot = host.getScriptSnapshot(fileName); - let signature = crypto.createHash('md5') + const snapshot = host.getScriptSnapshot(fileName); + const signature = crypto.createHash('md5') .update(snapshot.getText(0, snapshot.getLength())) .digest('base64'); return resolve({ @@ -95,10 +97,10 @@ function createTypeScriptBuilder(config, projectFile, cmd) { files: [] }); } - let output = service.getEmitOutput(fileName); - let files = []; + const output = service.getEmitOutput(fileName); + const files = []; let signature; - for (let file of output.outputFiles) { + for (const file of output.outputFiles) { if (!emitSourceMapsInStream && /\.js\.map$/.test(file.name)) { continue; } @@ -111,19 +113,19 @@ function createTypeScriptBuilder(config, projectFile, cmd) { continue; } } - let vinyl = new Vinyl({ + const vinyl = new Vinyl({ path: file.name, contents: Buffer.from(file.text), base: !config._emitWithoutBasePath && baseFor(host.getScriptSnapshot(fileName)) || undefined }); if (!emitSourceMapsInStream && /\.js$/.test(file.name)) { - let sourcemapFile = output.outputFiles.filter(f => /\.js\.map$/.test(f.name))[0]; + const sourcemapFile = output.outputFiles.filter(f => /\.js\.map$/.test(f.name))[0]; if (sourcemapFile) { - let extname = path.extname(vinyl.relative); - let basename = path.basename(vinyl.relative, extname); - let dirname = path.dirname(vinyl.relative); - let tsname = (dirname === '.' ? '' : dirname + '/') + basename + '.ts'; - let sourceMap = JSON.parse(sourcemapFile.text); + const extname = path.extname(vinyl.relative); + const basename = path.basename(vinyl.relative, extname); + const dirname = path.dirname(vinyl.relative); + const tsname = (dirname === '.' ? '' : dirname + '/') + basename + '.ts'; + const sourceMap = JSON.parse(sourcemapFile.text); sourceMap.sources[0] = tsname.replace(/\\/g, '/'); vinyl.sourceMap = sourceMap; } @@ -138,15 +140,15 @@ function createTypeScriptBuilder(config, projectFile, cmd) { }); }); } - let newErrors = Object.create(null); - let t1 = Date.now(); - let toBeEmitted = []; - let toBeCheckedSyntactically = []; - let toBeCheckedSemantically = []; - let filesWithChangedSignature = []; - let dependentFiles = []; - let newLastBuildVersion = new Map(); - for (let fileName of host.getScriptFileNames()) { + const newErrors = Object.create(null); + const t1 = Date.now(); + const toBeEmitted = []; + const toBeCheckedSyntactically = []; + const toBeCheckedSemantically = []; + const filesWithChangedSignature = []; + const dependentFiles = []; + const newLastBuildVersion = new Map(); + for (const fileName of host.getScriptFileNames()) { if (lastBuildVersion[fileName] !== host.getScriptVersion(fileName)) { toBeEmitted.push(fileName); toBeCheckedSyntactically.push(fileName); @@ -154,8 +156,8 @@ function createTypeScriptBuilder(config, projectFile, cmd) { } } return new Promise(resolve => { - let semanticCheckInfo = new Map(); - let seenAsDependentFile = new Set(); + const semanticCheckInfo = new Map(); + const seenAsDependentFile = new Set(); function workOnNext() { let promise; // let fileName: string; @@ -168,9 +170,9 @@ function createTypeScriptBuilder(config, projectFile, cmd) { } // (1st) emit code else if (toBeEmitted.length) { - let fileName = toBeEmitted.pop(); + const fileName = toBeEmitted.pop(); promise = emitSoon(fileName).then(value => { - for (let file of value.files) { + for (const file of value.files) { _log('[emit code]', file.path); out(file); } @@ -189,7 +191,7 @@ function createTypeScriptBuilder(config, projectFile, cmd) { } // (2nd) check syntax else if (toBeCheckedSyntactically.length) { - let fileName = toBeCheckedSyntactically.pop(); + const fileName = toBeCheckedSyntactically.pop(); _log('[check syntax]', fileName); promise = checkSyntaxSoon(fileName).then(diagnostics => { delete oldErrors[fileName]; @@ -224,7 +226,7 @@ function createTypeScriptBuilder(config, projectFile, cmd) { // (4th) check dependents else if (filesWithChangedSignature.length) { while (filesWithChangedSignature.length) { - let fileName = filesWithChangedSignature.pop(); + const fileName = filesWithChangedSignature.pop(); if (!isExternalModule(service.getProgram().getSourceFile(fileName))) { _log('[check semantics*]', fileName + ' is an internal module and it has changed shape -> check whatever hasn\'t been checked yet'); toBeCheckedSemantically.push(...host.getScriptFileNames()); @@ -243,7 +245,7 @@ function createTypeScriptBuilder(config, projectFile, cmd) { } if (fileName) { seenAsDependentFile.add(fileName); - let value = semanticCheckInfo.get(fileName); + const value = semanticCheckInfo.get(fileName); if (value === 0) { // already validated successfully -> look at dependents next host.collectDependents(fileName, dependentFiles); @@ -283,12 +285,10 @@ function createTypeScriptBuilder(config, projectFile, cmd) { }); oldErrors = newErrors; // print stats - if (config.verbose) { - const headNow = process.memoryUsage().heapUsed; - const MB = 1024 * 1024; - log('[tsb]', 'time:', colors.yellow((Date.now() - t1) + 'ms'), 'mem:', colors.cyan(Math.ceil(headNow / MB) + 'MB'), colors.bgCyan('delta: ' + Math.ceil((headNow - headUsed) / MB))); - headUsed = headNow; - } + const headNow = process.memoryUsage().heapUsed; + const MB = 1024 * 1024; + _log('[tsb]', `time: ${colors.yellow((Date.now() - t1) + 'ms')} + \nmem: ${colors.cyan(Math.ceil(headNow / MB) + 'MB')} ${colors.bgCyan('delta: ' + Math.ceil((headNow - headUsed) / MB))}`); + headUsed = headNow; }); } return { @@ -400,7 +400,7 @@ class LanguageServiceHost { } if (!old || old.getVersion() !== snapshot.getVersion()) { this._dependenciesRecomputeList.push(filename); - let node = this._dependencies.lookup(filename); + const node = this._dependencies.lookup(filename); if (node) { node.outgoing = Object.create(null); } @@ -479,7 +479,7 @@ class LanguageServiceHost { } } if (!found) { - for (let key in this._fileNameToDeclaredModule) { + for (const key in this._fileNameToDeclaredModule) { if (this._fileNameToDeclaredModule[key] && ~this._fileNameToDeclaredModule[key].indexOf(ref.fileName)) { this._dependencies.inertEdge(filename, key); } diff --git a/build/lib/tsb/builder.ts b/build/lib/tsb/builder.ts index d5bec6ee97b..b6d3b153f6a 100644 --- a/build/lib/tsb/builder.ts +++ b/build/lib/tsb/builder.ts @@ -7,13 +7,12 @@ import { statSync, readFileSync } from 'fs'; import * as path from 'path'; import * as crypto from 'crypto'; import * as utils from './utils'; -import * as log from 'fancy-log'; import * as colors from 'ansi-colors'; import * as ts from 'typescript'; import * as Vinyl from 'vinyl'; export interface IConfiguration { - verbose: boolean; + logFn: (topic: string, message: string) => void; _emitWithoutBasePath?: boolean; } @@ -39,25 +38,20 @@ function normalize(path: string): string { export function createTypeScriptBuilder(config: IConfiguration, projectFile: string, cmd: ts.ParsedCommandLine): ITypeScriptBuilder { - function _log(topic: string, message: string): void { - if (config.verbose) { - log(colors.cyan(topic), message); - } - } + const _log = config.logFn; - let host = new LanguageServiceHost(cmd, projectFile, _log), - service = ts.createLanguageService(host, ts.createDocumentRegistry()), - lastBuildVersion: { [path: string]: string } = Object.create(null), - lastDtsHash: { [path: string]: string } = Object.create(null), - userWantsDeclarations = cmd.options.declaration, - oldErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null), - headUsed = process.memoryUsage().heapUsed, - emitSourceMapsInStream = true; + const host = new LanguageServiceHost(cmd, projectFile, _log); + const service = ts.createLanguageService(host, ts.createDocumentRegistry()); + const lastBuildVersion: { [path: string]: string } = Object.create(null); + const lastDtsHash: { [path: string]: string } = Object.create(null); + const userWantsDeclarations = cmd.options.declaration; + let oldErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null); + let headUsed = process.memoryUsage().heapUsed; + let emitSourceMapsInStream = true; // always emit declaraction files host.getCompilationSettings().declaration = true; - function file(file: Vinyl): void { // support gulp-sourcemaps if ((file).sourceMap) { @@ -117,8 +111,8 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str if (/\.d\.ts$/.test(fileName)) { // if it's already a d.ts file just emit it signature - let snapshot = host.getScriptSnapshot(fileName); - let signature = crypto.createHash('md5') + const snapshot = host.getScriptSnapshot(fileName); + const signature = crypto.createHash('md5') .update(snapshot.getText(0, snapshot.getLength())) .digest('base64'); @@ -129,11 +123,11 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str }); } - let output = service.getEmitOutput(fileName); - let files: Vinyl[] = []; + const output = service.getEmitOutput(fileName); + const files: Vinyl[] = []; let signature: string | undefined; - for (let file of output.outputFiles) { + for (const file of output.outputFiles) { if (!emitSourceMapsInStream && /\.js\.map$/.test(file.name)) { continue; } @@ -149,22 +143,22 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str } } - let vinyl = new Vinyl({ + const vinyl = new Vinyl({ path: file.name, contents: Buffer.from(file.text), base: !config._emitWithoutBasePath && baseFor(host.getScriptSnapshot(fileName)) || undefined }); if (!emitSourceMapsInStream && /\.js$/.test(file.name)) { - let sourcemapFile = output.outputFiles.filter(f => /\.js\.map$/.test(f.name))[0]; + const sourcemapFile = output.outputFiles.filter(f => /\.js\.map$/.test(f.name))[0]; if (sourcemapFile) { - let extname = path.extname(vinyl.relative); - let basename = path.basename(vinyl.relative, extname); - let dirname = path.dirname(vinyl.relative); - let tsname = (dirname === '.' ? '' : dirname + '/') + basename + '.ts'; + const extname = path.extname(vinyl.relative); + const basename = path.basename(vinyl.relative, extname); + const dirname = path.dirname(vinyl.relative); + const tsname = (dirname === '.' ? '' : dirname + '/') + basename + '.ts'; - let sourceMap = JSON.parse(sourcemapFile.text); + const sourceMap = JSON.parse(sourcemapFile.text); sourceMap.sources[0] = tsname.replace(/\\/g, '/'); (vinyl).sourceMap = sourceMap; } @@ -182,17 +176,17 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str }); } - let newErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null); - let t1 = Date.now(); + const newErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null); + const t1 = Date.now(); - let toBeEmitted: string[] = []; - let toBeCheckedSyntactically: string[] = []; - let toBeCheckedSemantically: string[] = []; - let filesWithChangedSignature: string[] = []; - let dependentFiles: string[] = []; - let newLastBuildVersion = new Map(); + const toBeEmitted: string[] = []; + const toBeCheckedSyntactically: string[] = []; + const toBeCheckedSemantically: string[] = []; + const filesWithChangedSignature: string[] = []; + const dependentFiles: string[] = []; + const newLastBuildVersion = new Map(); - for (let fileName of host.getScriptFileNames()) { + for (const fileName of host.getScriptFileNames()) { if (lastBuildVersion[fileName] !== host.getScriptVersion(fileName)) { toBeEmitted.push(fileName); @@ -203,8 +197,8 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str return new Promise(resolve => { - let semanticCheckInfo = new Map(); - let seenAsDependentFile = new Set(); + const semanticCheckInfo = new Map(); + const seenAsDependentFile = new Set(); function workOnNext() { @@ -221,10 +215,10 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str // (1st) emit code else if (toBeEmitted.length) { - let fileName = toBeEmitted.pop()!; + const fileName = toBeEmitted.pop()!; promise = emitSoon(fileName).then(value => { - for (let file of value.files) { + for (const file of value.files) { _log('[emit code]', file.path); out(file); } @@ -246,7 +240,7 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str // (2nd) check syntax else if (toBeCheckedSyntactically.length) { - let fileName = toBeCheckedSyntactically.pop()!; + const fileName = toBeCheckedSyntactically.pop()!; _log('[check syntax]', fileName); promise = checkSyntaxSoon(fileName).then(diagnostics => { delete oldErrors[fileName]; @@ -286,7 +280,7 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str // (4th) check dependents else if (filesWithChangedSignature.length) { while (filesWithChangedSignature.length) { - let fileName = filesWithChangedSignature.pop()!; + const fileName = filesWithChangedSignature.pop()!; if (!isExternalModule(service.getProgram()!.getSourceFile(fileName)!)) { _log('[check semantics*]', fileName + ' is an internal module and it has changed shape -> check whatever hasn\'t been checked yet'); @@ -308,7 +302,7 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str } if (fileName) { seenAsDependentFile.add(fileName); - let value = semanticCheckInfo.get(fileName); + const value = semanticCheckInfo.get(fileName); if (value === 0) { // already validated successfully -> look at dependents next host.collectDependents(fileName, dependentFiles); @@ -355,15 +349,13 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str oldErrors = newErrors; // print stats - if (config.verbose) { - const headNow = process.memoryUsage().heapUsed; - const MB = 1024 * 1024; - log('[tsb]', - 'time:', colors.yellow((Date.now() - t1) + 'ms'), - 'mem:', colors.cyan(Math.ceil(headNow / MB) + 'MB'), colors.bgCyan('delta: ' + Math.ceil((headNow - headUsed) / MB)) - ); - headUsed = headNow; - } + const headNow = process.memoryUsage().heapUsed; + const MB = 1024 * 1024; + _log( + '[tsb]', + `time: ${colors.yellow((Date.now() - t1) + 'ms')} + \nmem: ${colors.cyan(Math.ceil(headNow / MB) + 'MB')} ${colors.bgCyan('delta: ' + Math.ceil((headNow - headUsed) / MB))}` + ); + headUsed = headNow; }); } @@ -507,7 +499,7 @@ class LanguageServiceHost implements ts.LanguageServiceHost { } if (!old || old.getVersion() !== snapshot.getVersion()) { this._dependenciesRecomputeList.push(filename); - let node = this._dependencies.lookup(filename); + const node = this._dependencies.lookup(filename); if (node) { node.outgoing = Object.create(null); } @@ -605,7 +597,7 @@ class LanguageServiceHost implements ts.LanguageServiceHost { } if (!found) { - for (let key in this._fileNameToDeclaredModule) { + for (const key in this._fileNameToDeclaredModule) { if (this._fileNameToDeclaredModule[key] && ~this._fileNameToDeclaredModule[key].indexOf(ref.fileName)) { this._dependencies.inertEdge(filename, key); } diff --git a/build/lib/tsb/index.js b/build/lib/tsb/index.js index bd30013092c..51806a479ea 100644 --- a/build/lib/tsb/index.js +++ b/build/lib/tsb/index.js @@ -13,6 +13,9 @@ const stream_1 = require("stream"); const path_1 = require("path"); const utils_1 = require("./utils"); const fs_1 = require("fs"); +const log = require("fancy-log"); +const colors = require("ansi-colors"); +const transpiler_1 = require("./transpiler"); class EmptyDuplex extends stream_1.Duplex { _write(_chunk, _encoding, callback) { callback(); } _read() { this.push(null); } @@ -23,7 +26,7 @@ function createNullCompiler() { return result; } const _defaultOnError = (err) => console.log(JSON.stringify(err, null, 4)); -function create(projectPath, existingOptions, verbose = false, onError = _defaultOnError) { +function create(projectPath, existingOptions, config, onError = _defaultOnError) { function printDiagnostic(diag) { if (!diag.file || !diag.start) { onError(ts.flattenDiagnosticMessageText(diag.messageText, '\n')); @@ -43,24 +46,64 @@ function create(projectPath, existingOptions, verbose = false, onError = _defaul cmdLine.errors.forEach(printDiagnostic); return createNullCompiler(); } - const _builder = builder.createTypeScriptBuilder({ verbose }, projectPath, cmdLine); - function createStream(token) { + function logFn(topic, message) { + if (config.verbose) { + log(colors.cyan(topic), message); + } + } + // FULL COMPILE stream doing transpile, syntax and semantic diagnostics + function createCompileStream(builder, token) { return through(function (file) { // give the file to the compiler if (file.isStream()) { this.emit('error', 'no support for streams'); return; } - _builder.file(file); + builder.file(file); }, function () { // start the compilation process - _builder.build(file => this.queue(file), printDiagnostic, token).catch(e => console.error(e)).then(() => this.queue(null)); + builder.build(file => this.queue(file), printDiagnostic, token).catch(e => console.error(e)).then(() => this.queue(null)); }); } - const result = (token) => createStream(token); + // TRANSPILE ONLY stream doing just TS to JS conversion + function createTranspileStream(transpiler) { + return through(function (file) { + // give the file to the compiler + if (file.isStream()) { + this.emit('error', 'no support for streams'); + return; + } + if (!file.contents) { + return; + } + if (!config.transpileOnlyIncludesDts && file.path.endsWith('.d.ts')) { + return; + } + if (!transpiler.onOutfile) { + transpiler.onOutfile = file => this.queue(file); + } + transpiler.transpile(file); + }, function () { + transpiler.join().then(() => { + this.queue(null); + transpiler.onOutfile = undefined; + }); + }); + } + let result; + if (config.transpileOnly) { + const transpiler = !config.transpileWithSwc + ? new transpiler_1.TscTranspiler(logFn, printDiagnostic, projectPath, cmdLine) + : new transpiler_1.SwcTranspiler(logFn, printDiagnostic, projectPath, cmdLine); + result = (() => createTranspileStream(transpiler)); + } + else { + const _builder = builder.createTypeScriptBuilder({ logFn }, projectPath, cmdLine); + result = ((token) => createCompileStream(_builder, token)); + } result.src = (opts) => { let _pos = 0; - let _fileNames = cmdLine.fileNames.slice(0); + const _fileNames = cmdLine.fileNames.slice(0); return new class extends stream_1.Readable { constructor() { super({ objectMode: true }); diff --git a/build/lib/tsb/index.ts b/build/lib/tsb/index.ts index 6e8e3d6fb77..0c5952cec34 100644 --- a/build/lib/tsb/index.ts +++ b/build/lib/tsb/index.ts @@ -11,6 +11,9 @@ import { Readable, Writable, Duplex } from 'stream'; import { dirname } from 'path'; import { strings } from './utils'; import { readFileSync, statSync } from 'fs'; +import * as log from 'fancy-log'; +import colors = require('ansi-colors'); +import { ITranspiler, SwcTranspiler, TscTranspiler } from './transpiler'; export interface IncrementalCompiler { (token?: any): Readable & Writable; @@ -33,7 +36,7 @@ const _defaultOnError = (err: string) => console.log(JSON.stringify(err, null, 4 export function create( projectPath: string, existingOptions: Partial, - verbose: boolean = false, + config: { verbose?: boolean; transpileOnly?: boolean; transpileOnlyIncludesDts?: boolean; transpileWithSwc?: boolean }, onError: (message: string) => void = _defaultOnError ): IncrementalCompiler { @@ -64,9 +67,14 @@ export function create( return createNullCompiler(); } - const _builder = builder.createTypeScriptBuilder({ verbose }, projectPath, cmdLine); + function logFn(topic: string, message: string): void { + if (config.verbose) { + log(colors.cyan(topic), message); + } + } - function createStream(token?: builder.CancellationToken): Readable & Writable { + // FULL COMPILE stream doing transpile, syntax and semantic diagnostics + function createCompileStream(builder: builder.ITypeScriptBuilder, token?: builder.CancellationToken): Readable & Writable { return through(function (this: through.ThroughStream, file: Vinyl) { // give the file to the compiler @@ -74,11 +82,11 @@ export function create( this.emit('error', 'no support for streams'); return; } - _builder.file(file); + builder.file(file); }, function (this: { queue(a: any): void }) { // start the compilation process - _builder.build( + builder.build( file => this.queue(file), printDiagnostic, token @@ -86,10 +94,50 @@ export function create( }); } - const result = (token: builder.CancellationToken) => createStream(token); + // TRANSPILE ONLY stream doing just TS to JS conversion + 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()) { + this.emit('error', 'no support for streams'); + return; + } + if (!file.contents) { + return; + } + if (!config.transpileOnlyIncludesDts && file.path.endsWith('.d.ts')) { + return; + } + + if (!transpiler.onOutfile) { + transpiler.onOutfile = file => this.queue(file); + } + + transpiler.transpile(file); + + }, function (this: { queue(a: any): void }) { + transpiler.join().then(() => { + this.queue(null); + transpiler.onOutfile = undefined; + }); + }); + } + + + let result: IncrementalCompiler; + if (config.transpileOnly) { + 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); + result = ((token: builder.CancellationToken) => createCompileStream(_builder, token)); + } + result.src = (opts?: { cwd?: string; base?: string }) => { let _pos = 0; - let _fileNames = cmdLine.fileNames.slice(0); + const _fileNames = cmdLine.fileNames.slice(0); return new class extends Readable { constructor() { super({ objectMode: true }); diff --git a/build/lib/tsb/transpiler.js b/build/lib/tsb/transpiler.js new file mode 100644 index 00000000000..e5e90128d09 --- /dev/null +++ b/build/lib/tsb/transpiler.js @@ -0,0 +1,314 @@ +"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; +Object.defineProperty(exports, "__esModule", { value: true }); +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"); +const node_os_1 = require("node:os"); +function transpile(tsSrc, options) { + const isAmd = /\n(import|export)/m.test(tsSrc); + if (!isAmd && options.compilerOptions?.module === ts.ModuleKind.AMD) { + // enforce NONE module-system for not-amd cases + options = { ...options, ...{ compilerOptions: { ...options.compilerOptions, module: ts.ModuleKind.None } } }; + } + const out = ts.transpileModule(tsSrc, options); + return { + jsSrc: out.outputText, + diag: out.diagnostics ?? [] + }; +} +if (!threads.isMainThread) { + // WORKER + threads.parentPort?.addListener('message', (req) => { + const res = { + jsSrcs: [], + diagnostics: [] + }; + for (const tsSrc of req.tsSrcs) { + const out = transpile(tsSrc, req.options); + res.jsSrcs.push(out.jsSrc); + res.diagnostics.push(out.diag); + } + 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++; + this._worker = new threads.Worker(__filename); + this._durations = []; + this._worker.addListener('message', (res) => { + if (!this._pending) { + console.error('RECEIVING data WITHOUT request'); + return; + } + const [resolve, reject, files, options, t1] = this._pending; + const outFiles = []; + const diag = []; + for (let i = 0; i < res.jsSrcs.length; i++) { + // inputs and outputs are aligned across the arrays + const file = files[i]; + const jsSrc = res.jsSrcs[i]; + const diag = res.diagnostics[i]; + if (diag.length > 0) { + diag.push(...diag); + continue; + } + let SuffixTypes; + (function (SuffixTypes) { + SuffixTypes[SuffixTypes["Dts"] = 5] = "Dts"; + SuffixTypes[SuffixTypes["Ts"] = 3] = "Ts"; + SuffixTypes[SuffixTypes["Unknown"] = 0] = "Unknown"; + })(SuffixTypes || (SuffixTypes = {})); + const suffixLen = file.path.endsWith('.d.ts') ? 5 /* SuffixTypes.Dts */ + : file.path.endsWith('.ts') ? 3 /* SuffixTypes.Ts */ + : 0 /* SuffixTypes.Unknown */; + // check if output of a DTS-files isn't just "empty" and iff so + // skip this file + if (suffixLen === 5 /* SuffixTypes.Dts */ && _isDefaultEmpty(jsSrc)) { + continue; + } + const outBase = options.compilerOptions?.outDir ?? file.base; + const outPath = outFileFn(file.path); + outFiles.push(new Vinyl({ + path: outPath, + base: outBase, + contents: Buffer.from(jsSrc), + })); + } + this._pending = undefined; + this._durations.push(Date.now() - t1); + if (diag.length > 0) { + reject(diag); + } + else { + resolve(outFiles); + } + }); + } + terminate() { + // console.log(`Worker#${this.id} ENDS after ${this._durations.length} jobs (total: ${this._durations.reduce((p, c) => p + c, 0)}, avg: ${this._durations.reduce((p, c) => p + c, 0) / this._durations.length})`); + this._worker.terminate(); + } + get isBusy() { + return this._pending !== undefined; + } + next(files, options) { + if (this._pending !== undefined) { + throw new Error('BUSY'); + } + return new Promise((resolve, reject) => { + this._pending = [resolve, reject, files, options, Date.now()]; + const req = { + options, + tsSrcs: files.map(file => String(file.contents)) + }; + this._worker.postMessage(req); + }); + } +} +TranspileWorker.pool = 1; +class TscTranspiler { + constructor(logFn, _onError, configFilePath, _cmdLine) { + this._onError = _onError; + this._cmdLine = _cmdLine; + this._workerPool = []; + this._queue = []; + this._allJobs = []; + logFn('Transpile', `will use ${TscTranspiler.P} transpile worker`); + this._outputFileNames = new OutputFileNameOracle(_cmdLine, configFilePath); + } + async join() { + // wait for all penindg jobs + this._consumeQueue(); + await Promise.allSettled(this._allJobs); + this._allJobs.length = 0; + // terminate all worker + this._workerPool.forEach(w => w.terminate()); + this._workerPool.length = 0; + } + transpile(file) { + if (this._cmdLine.options.noEmit) { + // not doing ANYTHING here + return; + } + const newLen = this._queue.push(file); + if (newLen > TscTranspiler.P ** 2) { + this._consumeQueue(); + } + } + _consumeQueue() { + if (this._queue.length === 0) { + // no work... + return; + } + // kinda LAZYily create workers + if (this._workerPool.length === 0) { + 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); + if (freeWorker.length === 0) { + // OK, they will pick up work themselves + return; + } + for (const worker of freeWorker) { + if (this._queue.length === 0) { + break; + } + const job = new Promise(resolve => { + const consume = () => { + const files = this._queue.splice(0, TscTranspiler.P); + if (files.length === 0) { + // DONE + resolve(undefined); + return; + } + // work on the NEXT file + // const [inFile, outFn] = req; + worker.next(files, { compilerOptions: this._cmdLine.options }).then(outFiles => { + if (this.onOutfile) { + outFiles.map(this.onOutfile, this); + } + consume(); + }).catch(err => { + this._onError(err); + }); + }; + consume(); + }); + this._allJobs.push(job); + } + } +} +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 new file mode 100644 index 00000000000..a82cbaef890 --- /dev/null +++ b/build/lib/tsb/transpiler.ts @@ -0,0 +1,407 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * 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'; +import { cpus } from 'node:os'; + +interface TranspileReq { + readonly tsSrcs: string[]; + readonly options: ts.TranspileOptions; +} + +interface TranspileRes { + readonly jsSrcs: string[]; + readonly diagnostics: ts.Diagnostic[][]; +} + +function transpile(tsSrc: string, options: ts.TranspileOptions): { jsSrc: string; diag: ts.Diagnostic[] } { + + const isAmd = /\n(import|export)/m.test(tsSrc); + if (!isAmd && options.compilerOptions?.module === ts.ModuleKind.AMD) { + // enforce NONE module-system for not-amd cases + options = { ...options, ...{ compilerOptions: { ...options.compilerOptions, module: ts.ModuleKind.None } } }; + } + const out = ts.transpileModule(tsSrc, options); + return { + jsSrc: out.outputText, + diag: out.diagnostics ?? [] + }; +} + +if (!threads.isMainThread) { + // WORKER + threads.parentPort?.addListener('message', (req: TranspileReq) => { + const res: TranspileRes = { + jsSrcs: [], + diagnostics: [] + }; + for (const tsSrc of req.tsSrcs) { + const out = transpile(tsSrc, req.options); + res.jsSrcs.push(out.jsSrc); + res.diagnostics.push(out.diag); + } + threads.parentPort!.postMessage(res); + }); +} + +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; + + readonly id = TranspileWorker.pool++; + + private _worker = new threads.Worker(__filename); + private _pending?: [resolve: Function, reject: Function, file: Vinyl[], options: ts.TranspileOptions, t1: number]; + private _durations: number[] = []; + + constructor(outFileFn: (fileName: string) => string) { + + this._worker.addListener('message', (res: TranspileRes) => { + if (!this._pending) { + console.error('RECEIVING data WITHOUT request'); + return; + } + + const [resolve, reject, files, options, t1] = this._pending; + + const outFiles: Vinyl[] = []; + const diag: ts.Diagnostic[] = []; + + for (let i = 0; i < res.jsSrcs.length; i++) { + // inputs and outputs are aligned across the arrays + const file = files[i]; + const jsSrc = res.jsSrcs[i]; + const diag = res.diagnostics[i]; + + if (diag.length > 0) { + diag.push(...diag); + continue; + } + const enum SuffixTypes { + Dts = 5, + Ts = 3, + Unknown = 0 + } + const suffixLen = file.path.endsWith('.d.ts') ? SuffixTypes.Dts + : file.path.endsWith('.ts') ? SuffixTypes.Ts + : SuffixTypes.Unknown; + + // check if output of a DTS-files isn't just "empty" and iff so + // skip this file + if (suffixLen === SuffixTypes.Dts && _isDefaultEmpty(jsSrc)) { + continue; + } + + const outBase = options.compilerOptions?.outDir ?? file.base; + const outPath = outFileFn(file.path); + + outFiles.push(new Vinyl({ + path: outPath, + base: outBase, + contents: Buffer.from(jsSrc), + })); + } + + this._pending = undefined; + this._durations.push(Date.now() - t1); + + if (diag.length > 0) { + reject(diag); + } else { + resolve(outFiles); + } + }); + } + + terminate() { + // console.log(`Worker#${this.id} ENDS after ${this._durations.length} jobs (total: ${this._durations.reduce((p, c) => p + c, 0)}, avg: ${this._durations.reduce((p, c) => p + c, 0) / this._durations.length})`); + this._worker.terminate(); + } + + get isBusy() { + return this._pending !== undefined; + } + + next(files: Vinyl[], options: ts.TranspileOptions) { + if (this._pending !== undefined) { + throw new Error('BUSY'); + } + return new Promise((resolve, reject) => { + this._pending = [resolve, reject, files, options, Date.now()]; + const req: TranspileReq = { + options, + tsSrcs: files.map(file => String(file.contents)) + }; + this._worker.postMessage(req); + }); + } +} + +export interface ITranspiler { + onOutfile?: (file: Vinyl) => void; + join(): Promise; + transpile(file: Vinyl): void; +} + +export class TscTranspiler implements ITranspiler { + + static P = Math.floor(cpus().length * .5); + + private readonly _outputFileNames: OutputFileNameOracle; + + + public onOutfile?: (file: Vinyl) => void; + + private _workerPool: TranspileWorker[] = []; + private _queue: Vinyl[] = []; + private _allJobs: Promise[] = []; + + constructor( + logFn: (topic: string, message: string) => void, + private readonly _onError: (err: any) => void, + configFilePath: string, + private readonly _cmdLine: ts.ParsedCommandLine + ) { + logFn('Transpile', `will use ${TscTranspiler.P} transpile worker`); + this._outputFileNames = new OutputFileNameOracle(_cmdLine, configFilePath); + } + + async join() { + // wait for all penindg jobs + this._consumeQueue(); + await Promise.allSettled(this._allJobs); + this._allJobs.length = 0; + + // terminate all worker + this._workerPool.forEach(w => w.terminate()); + this._workerPool.length = 0; + } + + + transpile(file: Vinyl) { + + if (this._cmdLine.options.noEmit) { + // not doing ANYTHING here + return; + } + + const newLen = this._queue.push(file); + if (newLen > TscTranspiler.P ** 2) { + this._consumeQueue(); + } + } + + private _consumeQueue(): void { + + if (this._queue.length === 0) { + // no work... + return; + } + + // kinda LAZYily create workers + if (this._workerPool.length === 0) { + 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); + if (freeWorker.length === 0) { + // OK, they will pick up work themselves + return; + } + + for (const worker of freeWorker) { + if (this._queue.length === 0) { + break; + } + + const job = new Promise(resolve => { + + const consume = () => { + const files = this._queue.splice(0, TscTranspiler.P); + if (files.length === 0) { + // DONE + resolve(undefined); + return; + } + // work on the NEXT file + // const [inFile, outFn] = req; + worker.next(files, { compilerOptions: this._cmdLine.options }).then(outFiles => { + if (this.onOutfile) { + outFiles.map(this.onOutfile, this); + } + consume(); + }).catch(err => { + this._onError(err); + }); + }; + + consume(); + }); + + this._allJobs.push(job); + } + } +} + +function _isDefaultEmpty(src: string): boolean { + return src + .replace('"use strict";', '') + .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/tsb/utils.js b/build/lib/tsb/utils.js index 810297dc246..cc8605758ce 100644 --- a/build/lib/tsb/utils.js +++ b/build/lib/tsb/utils.js @@ -30,7 +30,7 @@ var collections; } collections.lookupOrInsert = lookupOrInsert; function forEach(collection, callback) { - for (let key in collection) { + for (const key in collection) { if (hasOwnProperty.call(collection, key)) { callback({ key: key, diff --git a/build/lib/tsb/utils.ts b/build/lib/tsb/utils.ts index 295d873b63a..3b003e3a6e1 100644 --- a/build/lib/tsb/utils.ts +++ b/build/lib/tsb/utils.ts @@ -28,7 +28,7 @@ export module collections { } export function forEach(collection: { [keys: string]: T }, callback: (entry: { key: string; value: T }) => void): void { - for (let key in collection) { + for (const key in collection) { if (hasOwnProperty.call(collection, key)) { callback({ key: key, diff --git a/build/lib/util.js b/build/lib/util.js index 4efe2b3a046..3eae325612a 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -1,10 +1,10 @@ +"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.buildWebNodePaths = exports.createExternalLoaderConfig = exports.acquireWebNodePaths = exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.getVersion = exports.ensureDir = exports.rreddir = exports.rimraf = exports.rewriteSourceMappingURL = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.debounce = exports.incremental = void 0; +exports.buildWebNodePaths = exports.createExternalLoaderConfig = exports.acquireWebNodePaths = exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.ensureDir = exports.rreddir = exports.rimraf = exports.rewriteSourceMappingURL = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.debounce = exports.incremental = void 0; const es = require("event-stream"); const _debounce = require("debounce"); const _filter = require("gulp-filter"); @@ -13,7 +13,6 @@ const path = require("path"); const fs = require("fs"); const _rimraf = require("rimraf"); const VinylFile = require("vinyl"); -const git = require("./git"); const root = path.dirname(path.dirname(__dirname)); const NoCancellationToken = { isCancellationRequested: () => false }; function incremental(streamProvider, initial, supportsCancellation) { @@ -240,7 +239,7 @@ function _rreaddir(dirPath, prepend, result) { } } function rreddir(dirPath) { - let result = []; + const result = []; _rreaddir(dirPath, '', result); return result; } @@ -253,14 +252,6 @@ function ensureDir(dirPath) { fs.mkdirSync(dirPath); } exports.ensureDir = ensureDir; -function getVersion(root) { - let version = process.env['VSCODE_DISTRO_COMMIT'] || process.env['BUILD_SOURCEVERSION']; - if (!version || !/^[0-9a-f]{40}$/i.test(version.trim())) { - version = git.getVersion(root); - } - return version; -} -exports.getVersion = getVersion; function rebase(count) { return rename(f => { const parts = f.dirname ? f.dirname.split(/[\/\\]/) : []; @@ -336,6 +327,13 @@ function acquireWebNodePaths() { } nodePaths[key] = entryPoint; } + // @TODO lramos15 can we make this dynamic like the rest of the node paths + // Add these paths as well for 1DS SDK dependencies. + // Not sure why given the 1DS entrypoint then requires these modules + // they are not fetched from the right location and instead are fetched from out/ + nodePaths['@microsoft/dynamicproto-js'] = 'lib/dist/umd/dynamicproto-js.min.js'; + nodePaths['@microsoft/applicationinsights-shims'] = 'dist/umd/applicationinsights-shims.min.js'; + nodePaths['@microsoft/applicationinsights-core-js'] = 'browser/applicationinsights-core-js.min.js'; return nodePaths; } exports.acquireWebNodePaths = acquireWebNodePaths; @@ -344,7 +342,7 @@ function createExternalLoaderConfig(webEndpoint, commit, quality) { return undefined; } webEndpoint = webEndpoint + `/${quality}/${commit}`; - let nodePaths = acquireWebNodePaths(); + const nodePaths = acquireWebNodePaths(); Object.keys(nodePaths).map(function (key, _) { nodePaths[key] = `${webEndpoint}/node_modules/${key}/${nodePaths[key]}`; }); diff --git a/build/lib/util.ts b/build/lib/util.ts index e1cb4e70be0..bbe6c52ef41 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import * as es from 'event-stream'; import _debounce = require('debounce'); import * as _filter from 'gulp-filter'; @@ -16,7 +14,6 @@ import * as _rimraf from 'rimraf'; import * as VinylFile from 'vinyl'; import { ThroughStream } from 'through'; import * as sm from 'source-map'; -import * as git from './git'; const root = path.dirname(path.dirname(__dirname)); @@ -209,8 +206,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; @@ -306,7 +303,7 @@ function _rreaddir(dirPath: string, prepend: string, result: string[]): void { } export function rreddir(dirPath: string): string[] { - let result: string[] = []; + const result: string[] = []; _rreaddir(dirPath, '', result); return result; } @@ -319,16 +316,6 @@ export function ensureDir(dirPath: string): void { fs.mkdirSync(dirPath); } -export function getVersion(root: string): string | undefined { - let version = process.env['VSCODE_DISTRO_COMMIT'] || process.env['BUILD_SOURCEVERSION']; - - if (!version || !/^[0-9a-f]{40}$/i.test(version.trim())) { - version = git.getVersion(root); - } - - return version; -} - export function rebase(count: number): NodeJS.ReadWriteStream { return rename(f => { const parts = f.dirname ? f.dirname.split(/[\/\\]/) : []; @@ -415,6 +402,13 @@ export function acquireWebNodePaths() { nodePaths[key] = entryPoint; } + // @TODO lramos15 can we make this dynamic like the rest of the node paths + // Add these paths as well for 1DS SDK dependencies. + // Not sure why given the 1DS entrypoint then requires these modules + // they are not fetched from the right location and instead are fetched from out/ + nodePaths['@microsoft/dynamicproto-js'] = 'lib/dist/umd/dynamicproto-js.min.js'; + nodePaths['@microsoft/applicationinsights-shims'] = 'dist/umd/applicationinsights-shims.min.js'; + nodePaths['@microsoft/applicationinsights-core-js'] = 'browser/applicationinsights-core-js.min.js'; return nodePaths; } @@ -423,7 +417,7 @@ export function createExternalLoaderConfig(webEndpoint?: string, commit?: string return undefined; } webEndpoint = webEndpoint + `/${quality}/${commit}`; - let nodePaths = acquireWebNodePaths(); + const nodePaths = acquireWebNodePaths(); Object.keys(nodePaths).map(function (key, _) { nodePaths[key] = `${webEndpoint}/node_modules/${key}/${nodePaths[key]}`; }); @@ -455,4 +449,3 @@ export function buildWebNodePaths(outDir: string) { result.taskName = 'build-web-node-paths'; return result; } - 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..a6e2cdf1f5e --- /dev/null +++ b/build/linux/debian/dep-lists.js @@ -0,0 +1,144 @@ +"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)', + 'libcups2 (>= 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)', + 'libcups2 (>= 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)', + 'libcups2 (>= 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..528448a1961 --- /dev/null +++ b/build/linux/debian/dep-lists.ts @@ -0,0 +1,144 @@ +/*--------------------------------------------------------------------------------------------- + * 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)', + 'libcups2 (>= 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)', + 'libcups2 (>= 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)', + 'libcups2 (>= 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/extensions/vscode-notebook-tests/test/customRenderer.vsctestnb b/build/linux/debian/types.js similarity index 58% rename from extensions/vscode-notebook-tests/test/customRenderer.vsctestnb rename to build/linux/debian/types.js index a4a092d8349..93c92aac9c6 100644 --- a/extensions/vscode-notebook-tests/test/customRenderer.vsctestnb +++ b/build/linux/debian/types.js @@ -1,4 +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 1d91eb8de78..af20828097e 100644 --- a/build/linux/rpm/dependencies-generator.js +++ b/build/linux/dependencies-generator.js @@ -6,18 +6,45 @@ 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 95953ecaa24..34573c4ac12 100644 --- a/build/linux/rpm/dependencies-generator.ts +++ b/build/linux/dependencies-generator.ts @@ -6,21 +6,49 @@ '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']); @@ -40,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 { @@ -74,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/libcxx-fetcher.js b/build/linux/libcxx-fetcher.js index 52606aba169..64c7706ff62 100644 --- a/build/linux/libcxx-fetcher.js +++ b/build/linux/libcxx-fetcher.js @@ -1,11 +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. *--------------------------------------------------------------------------------------------*/ -// Can be removed once https://github.com/electron/electron-rebuild/pull/703 is available. -'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.downloadLibcxxObjects = exports.downloadLibcxxHeaders = void 0; +// Can be removed once https://github.com/electron/electron-rebuild/pull/703 is available. const debug = require("debug"); const extract = require("extract-zip"); const fs = require("fs-extra"); diff --git a/build/linux/libcxx-fetcher.ts b/build/linux/libcxx-fetcher.ts index 0e8f5ade255..a9b97a0d9a6 100644 --- a/build/linux/libcxx-fetcher.ts +++ b/build/linux/libcxx-fetcher.ts @@ -5,8 +5,6 @@ // Can be removed once https://github.com/electron/electron-rebuild/pull/703 is available. -'use strict'; - import * as debug from 'debug'; import * as extract from 'extract-zip'; import * as fs from 'fs-extra'; 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 99064a1f7e6..2339e3703b6 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', @@ -65,6 +53,7 @@ exports.referenceGeneratedDepsByArch = { 'libc.so.6(GLIBC_2.8)(64bit)', 'libc.so.6(GLIBC_2.9)(64bit)', 'libcairo.so.2()(64bit)', + 'libcups.so.2()(64bit)', 'libcurl.so.4()(64bit)', 'libdbus-1.so.3()(64bit)', 'libdl.so.2()(64bit)', @@ -74,10 +63,8 @@ exports.referenceGeneratedDepsByArch = { 'libgbm.so.1()(64bit)', 'libgcc_s.so.1()(64bit)', 'libgcc_s.so.1(GCC_3.0)(64bit)', - 'libgdk_pixbuf-2.0.so.0()(64bit)', 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', - 'libgmodule-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', 'libgtk-3.so.0()(64bit)', 'libm.so.6()(64bit)', @@ -147,6 +134,7 @@ exports.referenceGeneratedDepsByArch = { 'libc.so.6(GLIBC_2.8)', 'libc.so.6(GLIBC_2.9)', 'libcairo.so.2', + 'libcups.so.2', 'libcurl.so.4()(64bit)', 'libdbus-1.so.3', 'libdl.so.2', @@ -158,10 +146,8 @@ exports.referenceGeneratedDepsByArch = { 'libgcc_s.so.1(GCC_3.0)', 'libgcc_s.so.1(GCC_3.4)', 'libgcc_s.so.1(GCC_3.5)', - 'libgdk_pixbuf-2.0.so.0', 'libgio-2.0.so.0', 'libglib-2.0.so.0', - 'libgmodule-2.0.so.0', 'libgobject-2.0.so.0', 'libgtk-3.so.0', 'libgtk-3.so.0()(64bit)', @@ -237,6 +223,7 @@ exports.referenceGeneratedDepsByArch = { 'libc.so.6()(64bit)', 'libc.so.6(GLIBC_2.17)(64bit)', 'libcairo.so.2()(64bit)', + 'libcups.so.2()(64bit)', 'libcurl.so.4()(64bit)', 'libdbus-1.so.3()(64bit)', 'libdbus-1.so.3(LIBDBUS_1_3)(64bit)', @@ -249,10 +236,8 @@ exports.referenceGeneratedDepsByArch = { 'libgcc_s.so.1(GCC_3.0)(64bit)', 'libgcc_s.so.1(GCC_4.2.0)(64bit)', 'libgcc_s.so.1(GCC_4.5.0)(64bit)', - 'libgdk_pixbuf-2.0.so.0()(64bit)', 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', - 'libgmodule-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', 'libgtk-3.so.0()(64bit)', 'libm.so.6()(64bit)', diff --git a/build/linux/rpm/dep-lists.ts b/build/linux/rpm/dep-lists.ts index 524cc0d7edd..7df703fa060 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', @@ -65,6 +52,7 @@ export const referenceGeneratedDepsByArch = { 'libc.so.6(GLIBC_2.8)(64bit)', 'libc.so.6(GLIBC_2.9)(64bit)', 'libcairo.so.2()(64bit)', + 'libcups.so.2()(64bit)', 'libcurl.so.4()(64bit)', 'libdbus-1.so.3()(64bit)', 'libdl.so.2()(64bit)', @@ -74,10 +62,8 @@ export const referenceGeneratedDepsByArch = { 'libgbm.so.1()(64bit)', 'libgcc_s.so.1()(64bit)', 'libgcc_s.so.1(GCC_3.0)(64bit)', - 'libgdk_pixbuf-2.0.so.0()(64bit)', 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', - 'libgmodule-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', 'libgtk-3.so.0()(64bit)', 'libm.so.6()(64bit)', @@ -147,6 +133,7 @@ export const referenceGeneratedDepsByArch = { 'libc.so.6(GLIBC_2.8)', 'libc.so.6(GLIBC_2.9)', 'libcairo.so.2', + 'libcups.so.2', 'libcurl.so.4()(64bit)', 'libdbus-1.so.3', 'libdl.so.2', @@ -158,10 +145,8 @@ export const referenceGeneratedDepsByArch = { 'libgcc_s.so.1(GCC_3.0)', 'libgcc_s.so.1(GCC_3.4)', 'libgcc_s.so.1(GCC_3.5)', - 'libgdk_pixbuf-2.0.so.0', 'libgio-2.0.so.0', 'libglib-2.0.so.0', - 'libgmodule-2.0.so.0', 'libgobject-2.0.so.0', 'libgtk-3.so.0', 'libgtk-3.so.0()(64bit)', @@ -237,6 +222,7 @@ export const referenceGeneratedDepsByArch = { 'libc.so.6()(64bit)', 'libc.so.6(GLIBC_2.17)(64bit)', 'libcairo.so.2()(64bit)', + 'libcups.so.2()(64bit)', 'libcurl.so.4()(64bit)', 'libdbus-1.so.3()(64bit)', 'libdbus-1.so.3(LIBDBUS_1_3)(64bit)', @@ -249,10 +235,8 @@ export const referenceGeneratedDepsByArch = { 'libgcc_s.so.1(GCC_3.0)(64bit)', 'libgcc_s.so.1(GCC_4.2.0)(64bit)', 'libgcc_s.so.1(GCC_4.5.0)(64bit)', - 'libgdk_pixbuf-2.0.so.0()(64bit)', 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', - 'libgmodule-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', 'libgtk-3.so.0()(64bit)', 'libm.so.6()(64bit)', 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..f48942bf3e5 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -43,7 +43,7 @@ declare namespace monaco { #include(vs/base/common/uri): URI, UriComponents #include(vs/base/common/keyCodes): KeyCode #include(vs/editor/common/services/editorBaseApi): KeyMod -#include(vs/base/common/htmlContent): IMarkdownString +#include(vs/base/common/htmlContent): IMarkdownString, MarkdownStringTrustedOptions #include(vs/base/browser/keyboardEvent): IKeyboardEvent #include(vs/base/browser/mouseEvent): IMouseEvent #include(vs/editor/common/editorCommon): IScrollEvent @@ -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 23f57323e45..f820f39e222 100644 --- a/build/npm/dirs.js +++ b/build/npm/dirs.js @@ -23,13 +23,14 @@ exports.dirs = [ 'extensions/gulp', 'extensions/html-language-features', 'extensions/html-language-features/server', - 'extensions/image-preview', 'extensions/ipynb', 'extensions/jake', 'extensions/json-language-features', 'extensions/json-language-features/server', + 'extensions/markdown-language-features/server', 'extensions/markdown-language-features', 'extensions/markdown-math', + 'extensions/media-preview', 'extensions/merge-conflict', 'extensions/microsoft-authentication', 'extensions/notebook-renderers', @@ -41,8 +42,6 @@ exports.dirs = [ 'extensions/typescript-language-features', 'extensions/vscode-api-tests', 'extensions/vscode-colorize-tests', - 'extensions/vscode-custom-editor-tests', - 'extensions/vscode-notebook-tests', 'extensions/vscode-test-resolver', 'remote', 'remote/web', 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/preinstall.js b/build/npm/preinstall.js index a839653f75c..afefc404267 100644 --- a/build/npm/preinstall.js +++ b/build/npm/preinstall.js @@ -21,12 +21,19 @@ const path = require('path'); const fs = require('fs'); const cp = require('child_process'); const yarnVersion = cp.execSync('yarn -v', { encoding: 'utf8' }).trim(); -const parsedYarnVersion = /^(\d+)\.(\d+)\./.exec(yarnVersion); +const parsedYarnVersion = /^(\d+)\.(\d+)\.(\d+)/.exec(yarnVersion); const majorYarnVersion = parseInt(parsedYarnVersion[1]); const minorYarnVersion = parseInt(parsedYarnVersion[2]); +const patchYarnVersion = parseInt(parsedYarnVersion[3]); -if (majorYarnVersion < 1 || minorYarnVersion < 10) { - console.error('\033[1;31m*** Please use yarn >=1.10.1.\033[0;0m'); +if ( + majorYarnVersion < 1 || + majorYarnVersion === 1 && ( + minorYarnVersion < 10 || (minorYarnVersion === 10 && patchYarnVersion < 1) + ) || + majorYarnVersion >= 2 +) { + console.error('\033[1;31m*** Please use yarn >=1.10.1 and <2.\033[0;0m'); err = 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/npm/update-localization-extension.js b/build/npm/update-localization-extension.js index 1a689a189ea..b78674a7099 100644 --- a/build/npm/update-localization-extension.js +++ b/build/npm/update-localization-extension.js @@ -68,7 +68,7 @@ function update(options) { console.log(`Importing translations for ${languageId} form '${location}' to '${translationDataFolder}' ...`); let translationPaths = []; gulp.src(path.join(location, '**', languageId, '*.xlf'), { silent: false }) - .pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths, languageId === 'ps')) + .pipe(i18n.prepareI18nPackFiles(translationPaths)) .on('error', (error) => { console.log(`Error occurred while importing translations:`); translationPaths = undefined; diff --git a/build/package.json b/build/package.json index c259ad65063..6d4464865f3 100644 --- a/build/package.json +++ b/build/package.json @@ -40,19 +40,16 @@ "@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.1", + "got": "11.8.5", "gulp-merge-json": "^2.1.1", "gulp-shell": "^0.8.0", "jsonc-parser": "^2.3.0", diff --git a/build/setup-npm-registry.js b/build/setup-npm-registry.js new file mode 100644 index 00000000000..75a5fdc8131 --- /dev/null +++ b/build/setup-npm-registry.js @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const fs = require('fs').promises; +const path = require('path'); + +async function* getYarnLockFiles(dir) { + const files = await fs.readdir(dir); + + for (const file of files) { + const fullPath = path.join(dir, file); + const stat = await fs.stat(fullPath); + + if (stat.isDirectory()) { + yield* getYarnLockFiles(fullPath); + } else if (file === 'yarn.lock') { + yield fullPath; + } + } +} + +async function setup(url, file) { + let contents = await fs.readFile(file, 'utf8'); + contents = contents.replace(/https:\/\/registry\.[^.]+\.com\//g, url); + await fs.writeFile(file, contents); +} + +async function main(url) { + const root = process.cwd(); + + for await (const file of getYarnLockFiles(root)) { + console.log(`Enabling custom NPM registry: ${path.relative(root, file)}`); + await setup(url, file); + } +} + +main(process.argv[2]); 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/tsconfig.json b/build/tsconfig.json index de65bb698d3..ac3ce923add 100644 --- a/build/tsconfig.json +++ b/build/tsconfig.json @@ -3,6 +3,7 @@ "target": "es2020", "lib": ["ES2020"], "module": "commonjs", + "alwaysStrict": true, "removeComments": false, "preserveConstEnums": true, "sourceMap": false, diff --git a/build/win32/Cargo.lock b/build/win32/Cargo.lock index e27f58bf455..0601c70fb9e 100644 --- a/build/win32/Cargo.lock +++ b/build/win32/Cargo.lock @@ -1,258 +1,331 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "build_const" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = 3 [[package]] -name = "byteorder" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "chrono" -version = "0.4.0" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi", ] [[package]] -name = "crc" -version = "1.7.0" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "build_const" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" dependencies = [ - "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "build_const", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", ] [[package]] name = "inno_updater" -version = "0.8.2" +version = "0.9.0" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "crc", + "slog", + "slog-async", + "slog-term", + "winapi", ] [[package]] -name = "isatty" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.0.0" +name = "itoa" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "libc" -version = "0.2.36" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] -name = "num" -version = "0.1.41" +name = "num_threads" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "num-integer" -version = "0.1.35" +name = "once_cell" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-ident", ] [[package]] -name = "num-iter" -version = "0.1.34" +name = "quote" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] -[[package]] -name = "num-traits" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "redox_syscall" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", ] [[package]] -name = "slog" -version = "2.1.1" +name = "redox_users" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "rustversion" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" + +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" [[package]] name = "slog-async" -version = "2.2.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "766c59b252e62a34651412870ff55d8c4e6d04df19b43eecb2703e417b097ffe" dependencies = [ - "slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", ] [[package]] name = "slog-term" -version = "2.3.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87d29185c55b7b258b4f120eab00f48557d4d9bc814f41713f449d35b0f8977c" dependencies = [ - "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "slog", + "term", + "thread_local", + "time", +] + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "take_mut" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] name = "term" -version = "0.4.6" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-next", + "rustversion", + "winapi", ] [[package]] -name = "termion" -version = "1.5.1" +name = "thiserror" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "thread_local" -version = "0.3.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell", ] [[package]] name = "time" -version = "0.1.39" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "libc", + "num_threads", + "time-macros", ] [[package]] -name = "unreachable" -version = "1.0.0" +name = "time-macros" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" [[package]] -name = "void" -version = "1.0.2" +name = "unicode-ident" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.4" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" -"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" -"checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" -"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" -"checksum isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f2a233726c7bb76995cec749d59582e5664823b7245d4970354408f1d79a7a2" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" -"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" -"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" -"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9936036cc70fe4a8b2d338ab665900323290efb03983c86cbe235ae800ad8017" -"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6b13b17f4225771f7f15cece704a4e68d3a5f31278ed26367f497133398a18" -"checksum slog-async 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e319a30c08b004618d5f7ca2f2b1dad7b4623ba7fcb1a12846fc3b01e9eaa10" -"checksum slog-term 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bb5d9360b2b279b326824b3b4ca2402ead8a8138f0e5ec1900605c861bb6671" -"checksum take_mut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50b910a1174df4aeb5738e8a0e7253883cf7801de40d094175a5a557e487f4c5" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" -"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/build/win32/Cargo.toml b/build/win32/Cargo.toml new file mode 100644 index 00000000000..decae65f9e6 --- /dev/null +++ b/build/win32/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "inno_updater" +version = "0.9.0" +authors = ["Microsoft "] +build = "build.rs" + +[dependencies] +byteorder = "1" +crc = "^1.0.0" +slog = "2.1.1" +slog-async = "2.2.0" +slog-term = "2.3.0" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "^0.3.9", features = ["winuser", "libloaderapi", "commctrl", "processthreadsapi", "tlhelp32", "handleapi", "psapi", "errhandlingapi", "winbase", "shellapi"] } + +[profile.release] +lto = true +panic = 'abort' diff --git a/build/win32/code.iss b/build/win32/code.iss index e96ca4bde77..9376add416f 100644 --- a/build/win32/code.iss +++ b/build/win32/code.iss @@ -26,7 +26,7 @@ SetupIconFile={#RepoDir}\resources\win32\code.ico UninstallDisplayIcon={app}\{#ExeBasename}.exe ChangesEnvironment=true ChangesAssociations=true -MinVersion=6.1.7600 +MinVersion=6.2 SourceDir={#SourceDir} AppVersion={#Version} VersionInfoVersion={#RawVersion} @@ -77,7 +77,7 @@ Type: filesandordirs; Name: "{app}\_" Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 Name: "addcontextmenufiles"; Description: "{cm:AddContextMenuFiles,{#NameShort}}"; GroupDescription: "{cm:Other}"; Flags: unchecked -Name: "addcontextmenufolders"; Description: "{cm:AddContextMenuFolders,{#NameShort}}"; GroupDescription: "{cm:Other}"; Flags: unchecked +Name: "addcontextmenufolders"; Description: "{cm:AddContextMenuFolders,{#NameShort}}"; GroupDescription: "{cm:Other}"; Flags: unchecked; Check: not (IsWindows11OrLater and QualityIsInsiders) Name: "associatewithfiles"; Description: "{cm:AssociateWithFiles,{#NameShort}}"; GroupDescription: "{cm:Other}" Name: "addtopath"; Description: "{cm:AddToPath}"; GroupDescription: "{cm:Other}" Name: "runcode"; Description: "{cm:RunAfter,{#NameShort}}"; GroupDescription: "{cm:Other}"; Check: WizardSilent @@ -86,8 +86,9 @@ Name: "runcode"; Description: "{cm:RunAfter,{#NameShort}}"; GroupDescription: "{ Name: "{app}"; AfterInstall: DisableAppDirInheritance [Files] -Source: "*"; Excludes: "\CodeSignSummary*.md,\tools,\tools\*,\resources\app\product.json"; DestDir: "{code:GetDestDir}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "*"; Excludes: "\CodeSignSummary*.md,\tools,\tools\*,\appx,\appx\*,\resources\app\product.json"; DestDir: "{code:GetDestDir}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "tools\*"; DestDir: "{app}\tools"; Flags: ignoreversion +Source: "appx\*"; DestDir: "{app}\appx"; BeforeInstall: RemoveAppxPackage; AfterInstall: AddAppxPackage; Flags: ignoreversion; Check: IsWindows11OrLater and QualityIsInsiders Source: "{#ProductJsonPath}"; DestDir: "{code:GetDestDir}\resources\app"; Flags: ignoreversion [Icons] @@ -99,6 +100,9 @@ Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#NameLong}"; File Filename: "{app}\{#ExeBasename}.exe"; Description: "{cm:LaunchProgram,{#NameLong}}"; Tasks: runcode; Flags: nowait postinstall; Check: ShouldRunAfterUpdate Filename: "{app}\{#ExeBasename}.exe"; Description: "{cm:LaunchProgram,{#NameLong}}"; Flags: nowait postinstall; Check: WizardNotSilent +[UninstallRun] +Filename: "powershell.exe"; Parameters: "Invoke-Command -ScriptBlock {{Remove-AppxPackage -Package ""{#AppxPackageFullname}""}"; Check: IsWindows11OrLater and QualityIsInsiders; Flags: shellexec waituntilterminated runhidden + [Registry] #if "user" == InstallTarget #define SoftwareClassesRootKey "HKCU" @@ -1261,18 +1265,19 @@ Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBas Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBasename}.exe\shell\open"; ValueType: string; ValueName: "Icon"; ValueData: """{app}\{#ExeBasename}.exe""" Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBasename}.exe\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1""" -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufiles -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: addcontextmenufiles -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\background\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Drive\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Drive\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Drive\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}ContextMenu"; ValueType: expandsz; ValueName: "Title"; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey; Check: IsWindows11OrLater and QualityIsInsiders +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufiles; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: addcontextmenufiles; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\background\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Drive\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu,{#ShellNameShort}}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Drive\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders; Check: not (IsWindows11OrLater and QualityIsInsiders) +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Drive\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders; Check: not (IsWindows11OrLater and QualityIsInsiders) ; Environment #if "user" == InstallTarget @@ -1376,6 +1381,11 @@ begin Result := True; end; +function IsWindows11OrLater(): Boolean; +begin + Result := (GetWindowsVersion >= $0A0055F0); +end; + function GetAppMutex(Value: string): string; begin if IsBackgroundUpdate() then @@ -1400,6 +1410,37 @@ begin Result := 'false'; end; +function QualityIsInsiders(): boolean; +begin + if '{#Quality}' = 'insider' then + Result := True + else + Result := False; +end; + +procedure AddAppxPackage(); +var + AddAppxPackageResultCode: Integer; +begin + if WizardIsTaskSelected('addcontextmenufiles') then begin + ShellExec('', 'powershell.exe', '-Command ' + AddQuotes('Add-AppxPackage -Path ''' + ExpandConstant('{app}\appx\{#AppxPackage}') + ''' -ExternalLocation ''' + ExpandConstant('{app}\appx') + ''''), '', SW_HIDE, ewWaitUntilTerminated, AddAppxPackageResultCode); + RegDeleteKeyIncludingSubkeys({#EnvironmentRootKey}, 'Software\Classes\*\shell\{#RegValueName}'); + RegDeleteKeyIncludingSubkeys({#EnvironmentRootKey}, 'Software\Classes\directory\shell\{#RegValueName}'); + RegDeleteKeyIncludingSubkeys({#EnvironmentRootKey}, 'Software\Classes\directory\background\shell\{#RegValueName}'); + RegDeleteKeyIncludingSubkeys({#EnvironmentRootKey}, 'Software\Classes\Drive\shell\{#RegValueName}'); + end; +end; + +procedure RemoveAppxPackage(); +var + RemoveAppxPackageResultCode: Integer; +begin + ShellExec('', 'powershell.exe', '-Command ' + AddQuotes('Remove-AppxPackage -Package ''{#AppxPackageFullname}'''), '', SW_HIDE, ewWaitUntilTerminated, RemoveAppxPackageResultCode); + if not WizardIsTaskSelected('addcontextmenufiles') then begin + RegDeleteKeyIncludingSubkeys({#EnvironmentRootKey}, 'Software\Classes\{#RegValueName}ContextMenu'); + end; +end; + procedure CurStepChanged(CurStep: TSetupStep); var UpdateResultCode: Integer; @@ -1494,8 +1535,8 @@ 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); -end; \ No newline at end of file +end; diff --git a/build/win32/explorer-appx-fetcher.js b/build/win32/explorer-appx-fetcher.js new file mode 100644 index 00000000000..64b5ce9c117 --- /dev/null +++ b/build/win32/explorer-appx-fetcher.js @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.downloadExplorerAppx = void 0; +const debug = require("debug"); +const extract = require("extract-zip"); +const fs = require("fs-extra"); +const path = require("path"); +const product = require("../../product.json"); +const get_1 = require("@electron/get"); +const d = debug('explorer-appx-fetcher'); +async function downloadExplorerAppx(outDir, quality = 'stable', targetArch = 'x64') { + const fileNamePrefix = quality === 'insider' ? 'code_insiders' : 'code'; + const fileName = `${fileNamePrefix}_explorer_${targetArch}.zip`; + if (await fs.pathExists(path.resolve(outDir, 'resources.pri'))) { + return; + } + if (!await fs.pathExists(outDir)) { + await fs.mkdirp(outDir); + } + d(`downloading ${fileName}`); + const artifact = await (0, get_1.downloadArtifact)({ + isGeneric: true, + version: '3.0.4', + artifactName: fileName, + unsafelyDisableChecksums: true, + mirrorOptions: { + mirror: 'https://github.com/microsoft/vscode-explorer-command/releases/download/', + customDir: '3.0.4', + customFilename: fileName + } + }); + d(`unpacking from ${fileName}`); + await extract(artifact, { dir: outDir }); +} +exports.downloadExplorerAppx = downloadExplorerAppx; +async function main() { + const outputDir = process.env['VSCODE_EXPLORER_APPX_DIR']; + let arch = process.env['VSCODE_ARCH']; + if (!outputDir) { + throw new Error('Required build env not set'); + } + if (arch === 'ia32') { + arch = 'x86'; + } + await downloadExplorerAppx(outputDir, product.quality, arch); +} +if (require.main === module) { + main().catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/win32/explorer-appx-fetcher.ts b/build/win32/explorer-appx-fetcher.ts new file mode 100644 index 00000000000..9f49d954474 --- /dev/null +++ b/build/win32/explorer-appx-fetcher.ts @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as debug from 'debug'; +import * as extract from 'extract-zip'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import * as product from '../../product.json'; +import { downloadArtifact } from '@electron/get'; + +const d = debug('explorer-appx-fetcher'); + +export async function downloadExplorerAppx(outDir: string, quality: string = 'stable', targetArch: string = 'x64'): Promise { + const fileNamePrefix = quality === 'insider' ? 'code_insiders' : 'code'; + const fileName = `${fileNamePrefix}_explorer_${targetArch}.zip`; + + if (await fs.pathExists(path.resolve(outDir, 'resources.pri'))) { + return; + } + + if (!await fs.pathExists(outDir)) { + await fs.mkdirp(outDir); + } + + d(`downloading ${fileName}`); + const artifact = await downloadArtifact({ + isGeneric: true, + version: '3.0.4', + artifactName: fileName, + unsafelyDisableChecksums: true, + mirrorOptions: { + mirror: 'https://github.com/microsoft/vscode-explorer-command/releases/download/', + customDir: '3.0.4', + customFilename: fileName + } + }); + + d(`unpacking from ${fileName}`); + await extract(artifact, { dir: outDir }); +} + +async function main(): Promise { + const outputDir = process.env['VSCODE_EXPLORER_APPX_DIR']; + let arch = process.env['VSCODE_ARCH']; + + if (!outputDir) { + throw new Error('Required build env not set'); + } + + if (arch === 'ia32') { + arch = 'x86'; + } + + await downloadExplorerAppx(outputDir, (product as any).quality, arch); +} + +if (require.main === module) { + main().catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/win32/inno_updater.exe b/build/win32/inno_updater.exe index 8c532b9eb5e..fea47a59c9d 100644 Binary files a/build/win32/inno_updater.exe and b/build/win32/inno_updater.exe differ diff --git a/build/yarn.lock b/build/yarn.lock index d65a62ebce3..27bc4dd9a10 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" @@ -523,9 +502,9 @@ integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== "@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== + version "16.11.64" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.64.tgz#9171f327298b619e2c52238b120c19056415d820" + integrity sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q== "@types/p-limit@^2.2.0": version "2.2.0" @@ -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== @@ -1067,17 +919,17 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable-request@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58" - integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw== +cacheable-request@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== dependencies: clone-response "^1.0.2" get-stream "^5.1.0" http-cache-semantics "^4.0.0" keyv "^4.0.0" lowercase-keys "^2.0.0" - normalize-url "^4.1.0" + normalize-url "^6.0.1" responselike "^2.0.0" call-bind@^1.0.0: @@ -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,29 +1730,17 @@ 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.1: - version "11.8.1" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.1.tgz#df04adfaf2e782babb3daabc79139feec2f7e85d" - integrity sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q== +got@11.8.5: + version "11.8.5" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" + integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== dependencies: "@sindresorhus/is" "^4.0.0" "@szmarczak/http-timer" "^4.0.5" "@types/cacheable-request" "^6.0.1" "@types/responselike" "^1.0.0" cacheable-lookup "^5.0.3" - cacheable-request "^7.0.1" + cacheable-request "^7.0.2" decompress-response "^6.0.0" http2-wrapper "^1.0.0-beta.5.2" lowercase-keys "^2.0.0" @@ -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" @@ -2604,6 +2342,11 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + npm-conf@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" @@ -2734,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" @@ -2749,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== @@ -2865,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" @@ -2950,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" @@ -2974,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" @@ -3006,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== @@ -3028,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" @@ -3059,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" @@ -3092,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" @@ -3117,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" @@ -3326,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" @@ -3341,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 e969eb826e9..b2ab858f969 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -32,20 +32,6 @@ "Copyright (c) tunnel-agent authors" ] }, - { - // Reason: Waiting for https://github.com/segmentio/noop-logger/issues/2 - "name": "noop-logger", - "fullLicenseText": [ - "This project is licensed under the MIT license.", - "Copyrights are respective of each contributor listed at the beginning of each definition file.", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." - ] - }, { // Reason: The license at https://github.com/rbuckton/reflect-metadata/blob/master/LICENSE // does not include a clear Copyright statement (it's in https://github.com/rbuckton/reflect-metadata/blob/master/CopyrightNotice.txt). @@ -102,36 +88,6 @@ "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: Repository lacks license text. - // https://github.com/othiym23/emitter-listener/blob/master/package.json declares BSD-2-Clause. - // https://github.com/othiym23/emitter-listener/issues/3 - "name": "emitter-listener", - "fullLicenseText": [ - "BSD 2-Clause \"Simplified\" License", - "Copyright (c) 2018, Forrest L Norvell ", - "", - "Redistribution and use in source and binary forms, with or without", - "modification, are permitted provided that the following conditions are met:", - "", - "1. Redistributions of source code must retain the above copyright notice, this", - " list of conditions and the following disclaimer.", - "2. Redistributions in binary form must reproduce the above copyright notice,", - " this list of conditions and the following disclaimer in the documentation", - " and/or other materials provided with the distribution.", - "", - "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND", - "ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED", - "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE", - "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR", - "ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES", - "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;", - "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND", - "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT", - "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS", - "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." - ] - }, { // Reason: Repository lacks license text. // https://github.com/tjwebb/fnv-plus/blob/master/package.json declares MIT. @@ -147,5 +103,209 @@ "", "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." ] + }, + { + "name": "@vscode/win32-app-container-tokens", + "fullLicenseText": [ + "MIT License", + "", + "Copyright (c) Microsoft Corporation.", + "", + "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": "@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." + ] + }, + { + // Reason: The substack org has been deleted on GH + "name": "concat-map", + "fullLicenseText": [ + "This software is released under the MIT license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of", + "this software and associated documentation files (the \"Software\"), to deal in", + "the Software without restriction, including without limitation the rights to", + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software is furnished to do so,", + "subject to the following conditions:", + "", + "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: The substack org has been deleted on GH + "name": "github-from-package", + "fullLicenseText": [ + "This software is released under the MIT license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of", + "this software and associated documentation files (the \"Software\"), to deal in", + "the Software without restriction, including without limitation the rights to", + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software is furnished to do so,", + "subject to the following conditions:", + "", + "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: The substack org has been deleted on GH + "name": "minimist", + "fullLicenseText": [ + "This software is released under the MIT license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of", + "this software and associated documentation files (the \"Software\"), to deal in", + "the Software without restriction, including without limitation the rights to", + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software is furnished to do so,", + "subject to the following conditions:", + "", + "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: The substack org has been deleted on GH + "name": "mkdirp", + "fullLicenseText": [ + "Copyright 2010 James Halliday (mail@substack.net)", + "", + "This project is free software released under the MIT/X11 license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", + "", + "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: repo URI is wrong on crate, pending https://github.com/warp-tech/russh/pull/53 + "name": "russh-cryptovec", + "fullLicenseTextUri": "https://raw.githubusercontent.com/warp-tech/russh/1da80d0d599b6ee2d257c544c0d6af4f649c9029/LICENSE-2.0.txt" + }, + { + // Reason: repo URI is wrong on crate, pending https://github.com/warp-tech/russh/pull/53 + "name": "russh-keys", + "fullLicenseTextUri": "https://raw.githubusercontent.com/warp-tech/russh/1da80d0d599b6ee2d257c544c0d6af4f649c9029/LICENSE-2.0.txt" + }, + { + // Reason: license is in a subdirectory in repo + "name": "dirs-next", + "fullLicenseTextUri": "https://raw.githubusercontent.com/xdg-rs/dirs/af4aa39daba0ac68e222962a5aca17360158b7cc/dirs/LICENSE-MIT" + }, + { + // Reason: license is in a subdirectory in repo + "name": "openssl", + "fullLicenseTextUri": "https://raw.githubusercontent.com/sfackler/rust-openssl/e43eb58540b27a17f8029c397e3edc12bbc9011f/openssl/LICENSE" + }, + { + // Reason: license is in a subdirectory in repo + "name": "openssl-sys", + "fullLicenseTextUri": "https://raw.githubusercontent.com/sfackler/rust-openssl/e43eb58540b27a17f8029c397e3edc12bbc9011f/openssl-sys/LICENSE-MIT" + }, + { + // Reason: Missing license file + "name": "openssl-macros", + "fullLicenseText": [ + "This software is released under the MIT license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of", + "this software and associated documentation files (the \"Software\"), to deal in", + "the Software without restriction, including without limitation the rights to", + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software is furnished to do so,", + "subject to the following conditions:", + "", + "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 f87b67727c9..521f2082aa5 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "chromium", "repositoryUrl": "https://chromium.googlesource.com/chromium/src", - "commitHash": "e2aa76f05f3a6ccadbf43e37f5dfc195cc090b6a" + "commitHash": "16e28102fdf876ce6d136674ba66343ede07441f" } }, "licenseDetail": [ @@ -40,7 +40,475 @@ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ], "isOnlyProductionDependency": true, - "version": "98.0.4758.141" + "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": { + "type": "other", + "other": { + "name": "H.264/AVC Video Standard", + "downloadUrl": "https://chromium.googlesource.com/chromium/third_party/ffmpeg", + "version": "4.4.git" + } + }, + "licenseDetail": [ + "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." + ], + "version": "H.264 (08/21)", + "isOnlyProductionDependency": true, + "license": "OTHER" }, { "component": { @@ -48,11 +516,11 @@ "git": { "name": "nodejs", "repositoryUrl": "https://github.com/nodejs/node", - "commitHash": "40ecd5601193c316e62e9216e8a4259130686208" + "commitHash": "442e84a358d75152556b5d087e4dd6a51615330d" } }, "isOnlyProductionDependency": true, - "version": "16.13.0" + "version": "16.14.2" }, { "component": { @@ -60,12 +528,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "3a1945bd6c62459a457bd8d0b922259234816e22" + "commitHash": "0e6da36264d52656d5cd36a4c15937a6a6ca778e" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "17.4.6" + "version": "19.0.17" }, { "component": { @@ -539,6 +1007,98 @@ "isOnlyProductionDependency": true, "license": "MIT", "version": "0.10.0" + }, + { + "name": "@vscode/win32-app-container-tokens", + "component": { + "type": "git", + "git": { + "name": "vscode-win32-app-container-tokens", + "repositoryUrl": "https://github.com/microsoft/vscode-win32-app-container-tokens", + "commitHash": "5b871f95fd9cb8efa8ee9a80600510d5e5339137" + } + }, + "licenseDetail": [ + "MIT License", + "", + "Copyright (c) Microsoft Corporation.", + "", + "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" + ] + }, + { + "component": { + "type": "npm", + "npm": { + "name": "@iktakahiro/markdown-it-katex", + "version": "4.0.2" + } + }, + "repositoryUrl": "https://github.com/mjbvz/markdown-it-katex", + "licenseDetail": [ + "The MIT License (MIT)", + "", + "Copyright (c) 2016 Waylon Flinn", + "", + "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.", + "", + "---", + "", + "The MIT License (MIT)", + "", + "Copyright (c) 2018 Takahiro Ethan Ikeuchi @iktakahiro", + "", + "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." + ], + "license": "MIT" } ], "version": 1 diff --git a/cli/.cargo/config.toml b/cli/.cargo/config.toml new file mode 100644 index 00000000000..35c67ad3d28 --- /dev/null +++ b/cli/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.'cfg(all(windows, target_env = "msvc"))'] +rustflags = ["-C", "target-feature=+crt-static"] diff --git a/cli/CONTRIBUTING.md b/cli/CONTRIBUTING.md new file mode 100644 index 00000000000..d119f1ac98a --- /dev/null +++ b/cli/CONTRIBUTING.md @@ -0,0 +1,20 @@ +# Setup + +0. Clone, and then run `git submodule update --init --recursive` +1. Get the extensions: [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) and [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb) +2. Ensure your workspace is set to the `launcher` folder being the root. + +## Building the CLI on Windows + +For the moment, we require OpenSSL on Windows, where it is not usually installed by default. To install it: + +1. Install (clone) vcpkg [using their instructions](https://github.com/Microsoft/vcpkg#quick-start-windows) +1. Add the location of the `vcpkg` directory to your system or user PATH. +1. Run`vcpkg install openssl:x64-windows-static-md` (after restarting your terminal for PATH changes to apply) +1. You should be able to then `cargo build` successfully + +OpenSSL is needed for the key exchange we do when forwarding Basis tunnels. When all interested Basis clients support ED25519, we would be able to solely use libsodium. At the time of writing however, there is [no active development](https://chromestatus.com/feature/4913922408710144) on this in Chromium. + +# Debug + +1. You can use the Debug tasks already configured to run the launcher. diff --git a/cli/Cargo.lock b/cli/Cargo.lock new file mode 100644 index 00000000000..4ee1f5aae98 --- /dev/null +++ b/cli/Cargo.lock @@ -0,0 +1,2704 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "async-io" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" +dependencies = [ + "autocfg", + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-trait" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a90ec2df9600c28a01c56c4784c9207a96d2451833aeceb8cc97e4c9548bb78" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "cache-padded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "serde", + "time", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "clap" +version = "3.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "code-cli" +version = "0.1.0" +dependencies = [ + "async-trait", + "atty", + "chrono", + "clap", + "clap_lex", + "dialoguer", + "dirs 4.0.0", + "flate2", + "futures", + "gethostname", + "hyper", + "indicatif", + "keyring", + "lazy_static", + "libc", + "log", + "open", + "opentelemetry", + "opentelemetry-application-insights", + "rand 0.8.5", + "regex", + "reqwest", + "rmp-serde", + "serde", + "serde_bytes", + "serde_json", + "sysinfo", + "tar", + "tempfile", + "tokio", + "tokio-util", + "tunnels", + "url", + "uuid", + "windows-service", + "winreg", + "zip", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "console" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "unicode-width", + "winapi", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cxx" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dialoguer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1" +dependencies = [ + "console", + "tempfile", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enumflags2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "err-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34a887c8df3ed90498c1c437ce21f211c8e27672921a8ffa293cb8d6d4caa9e" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "rustversion", + "syn", + "synstructure", +] + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "filetime" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" + +[[package]] +name = "futures-executor" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" + +[[package]] +name = "futures-task" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" + +[[package]] +name = "futures-util" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "h2" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "indicatif" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" +dependencies = [ + "console", + "lazy_static", + "number_prefix", + "regex", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keyring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38fb8399ddcabfccb274577a8d90f0653e0b5b5977797c1c8834ad09839a10e5" +dependencies = [ + "byteorder", + "secret-service", + "security-framework", + "winapi", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" + +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "miniz_oxide" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nb-connect" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1bb540dc6ef51cfe1916ec038ce7a620daf3a111e2502d745197cd53d6bca15" +dependencies = [ + "libc", + "socket2", +] + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "num-complex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "open" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2423ffbf445b82e58c3b1543655968923dd06f85432f10be2bb4f1b7122f98c" +dependencies = [ + "pathdiff", + "windows-sys", +] + +[[package]] +name = "openssl" +version = "0.10.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "111.22.0+1.1.1q" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5230151e44c0f05157effb743e8d517472843121cf9243e8b81393edb5acd9ce" +dependencies = [ + "autocfg", + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "opentelemetry" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d6c3d7288a106c0a363e4b0e8d308058d56902adefb16f4936f417ffef086e" +dependencies = [ + "opentelemetry_api", + "opentelemetry_sdk", +] + +[[package]] +name = "opentelemetry-application-insights" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e592c598da4cbf1b4c4c8c07df4d3fb3a0202326cccf90621dbf23286cb79ea6" +dependencies = [ + "bytes", + "chrono", + "flate2", + "http", + "once_cell", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-semantic-conventions", + "reqwest", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "opentelemetry-http" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc79add46364183ece1a4542592ca593e6421c60807232f5b8f7a31703825d" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry_api", + "reqwest", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b02e0230abb0ab6636d18e2ba8fa02903ea63772281340ccac18e0af3ec9eeb" +dependencies = [ + "opentelemetry", +] + +[[package]] +name = "opentelemetry_api" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c24f96e21e7acc813c7a8394ee94978929db2bcc46cf6b5014fc612bf7760c22" +dependencies = [ + "futures-channel", + "futures-util", + "indexmap", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca41c4933371b61c2a2f214bf16931499af4ec90543604ec828f7a625c09113" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "once_cell", + "opentelemetry_api", + "percent-encoding", + "rand 0.8.5", + "thiserror", + "tokio", + "tokio-stream", +] + +[[package]] +name = "os_str_bytes" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "polling" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" +dependencies = [ + "autocfg", + "cfg-if", + "libc", + "log", + "wepoll-ffi", + "winapi", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +dependencies = [ + "once_cell", + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.7", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "rmp" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "russh" +version = "0.34.0-beta.16" +source = "git+https://github.com/microsoft/vscode-russh?branch=main#d22cf71d9ea36751322eeb9aa1e8c438a3aa1aef" +dependencies = [ + "bitflags", + "byteorder", + "digest", + "flate2", + "futures", + "generic-array", + "hex-literal", + "hmac", + "log", + "num-bigint", + "once_cell", + "openssl", + "rand 0.8.5", + "russh-cryptovec", + "russh-keys", + "sha1", + "sha2", + "subtle", + "thiserror", + "tokio", +] + +[[package]] +name = "russh-cryptovec" +version = "0.7.0-beta.1" +source = "git+https://github.com/microsoft/vscode-russh?branch=main#d22cf71d9ea36751322eeb9aa1e8c438a3aa1aef" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "russh-keys" +version = "0.22.0-beta.7" +source = "git+https://github.com/microsoft/vscode-russh?branch=main#d22cf71d9ea36751322eeb9aa1e8c438a3aa1aef" +dependencies = [ + "bit-vec", + "byteorder", + "data-encoding", + "dirs 3.0.2", + "futures", + "inout", + "log", + "md5", + "num-bigint", + "num-integer", + "openssl", + "rand 0.7.3", + "rand_core 0.5.1", + "russh-cryptovec", + "serde", + "serde_derive", + "sha2", + "thiserror", + "tokio", + "tokio-stream", + "yasna", +] + +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + +[[package]] +name = "secret-service" +version = "2.0.2" +source = "git+https://github.com/microsoft/vscode-secret-service-rs?rev=30f0414108a122d6f2bfc28a5425d0dac9738518#30f0414108a122d6f2bfc28a5425d0dac9738518" +dependencies = [ + "lazy_static", + "num", + "openssl", + "rand 0.8.5", + "serde", + "zbus", + "zbus_macros", + "zvariant", + "zvariant_derive", +] + +[[package]] +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "sysinfo" +version = "0.23.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3977ec2e0520829be45c8a2df70db2bf364714d8a748316a10c3c35d4d2b01c9" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "winapi", +] + +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +dependencies = [ + "futures-util", + "log", + "native-tls", + "tokio", + "tokio-native-tls", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "tungstenite" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "native-tls", + "rand 0.8.5", + "sha-1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "tunnels" +version = "0.1.0" +source = "git+https://github.com/microsoft/dev-tunnels?rev=3870e9133dfb9557774521bb447827f19b26e55d#3870e9133dfb9557774521bb447827f19b26e55d" +dependencies = [ + "async-trait", + "chrono", + "futures", + "log", + "reqwest", + "russh", + "russh-keys", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tokio-util", + "tungstenite", + "url", + "uuid", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.7", + "serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-service" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917fdb865e7ff03af9dd86609f8767bc88fefba89e8efd569de8e208af8724b3" +dependencies = [ + "bitflags", + "err-derive", + "widestring", + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + +[[package]] +name = "yasna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e262a29d0e61ccf2b6190d7050d4b237535fc76ce4c1210d9caa316f71dffa75" +dependencies = [ + "bit-vec", + "num-bigint", +] + +[[package]] +name = "zbus" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cbeb2291cd7267a94489b71376eda33496c1b9881adf6b36f26cc2779f3fc49" +dependencies = [ + "async-io", + "byteorder", + "derivative", + "enumflags2", + "fastrand", + "futures", + "nb-connect", + "nix", + "once_cell", + "polling", + "scoped-tls", + "serde", + "serde_repr", + "zbus_macros", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa3959a7847cf95e3d51e312856617c5b1b77191176c65a79a5f14d778bbe0a6" +dependencies = [ + "proc-macro-crate 0.1.5", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "crc32fast", + "flate2", + "thiserror", + "time", +] + +[[package]] +name = "zvariant" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68c7b55f2074489b7e8e07d2d0a6ee6b4f233867a653c664d8020ba53692525" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ca5e22593eb4212382d60d26350065bf2a02c34b85bc850474a74b589a3de9" +dependencies = [ + "proc-macro-crate 1.2.1", + "proc-macro2", + "quote", + "syn", +] diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 00000000000..dccd4a32c42 --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "code-cli" +version = "0.1.0" +edition = "2021" +default-run = "code" + +[lib] +name = "cli" +path = "src/lib.rs" + +[[bin]] +name = "code" + +[dependencies] +futures = "0.3" +clap = { version = "3.0", features = ["derive", "env"] } +open = { version = "2.1.0" } +reqwest = { version = "0.11.9", default-features = false, features = ["json", "stream", "native-tls-vendored"] } +tokio = { version = "1.20", features = ["full"] } +tokio-util = { version = "0.7", features = ["compat"] } +flate2 = { version = "1.0.22" } +zip = { version = "0.5.13", default-features = false, features = ["time", "deflate"] } +regex = { version = "1.5.5" } +lazy_static = { version = "1.4.0" } +sysinfo = { version = "0.23.5" } +serde = { version = "1.0", features = ["derive"] } +serde_json = { version = "1.0" } +rmp-serde = "1.0" +uuid = { version = "0.8.2", features = ["serde", "v4"] } +dirs = "4.0.0" +rand = "0.8.5" +atty = "0.2.14" +opentelemetry = { version = "0.18.0", features = ["rt-tokio"] } +opentelemetry-application-insights = { version = "0.22.0", features = ["reqwest-client-vendored-tls"] } +serde_bytes = "0.11.5" +chrono = { version = "0.4", features = ["serde"] } +gethostname = "0.2.3" +libc = "0.2" +tunnels = { git = "https://github.com/microsoft/dev-tunnels", rev = "3870e9133dfb9557774521bb447827f19b26e55d", default-features = false, features = ["connections", "vendored-openssl"] } +keyring = "1.1" +dialoguer = "0.10" +hyper = "0.14" +indicatif = "0.16" +tempfile = "3.3" +clap_lex = "0.2" +url = "2.3" +async-trait = "0.1" +log = "0.4" + +[target.'cfg(windows)'.dependencies] +windows-service = "0.5" +winreg = "0.10" + +[target.'cfg(target_os = "linux")'.dependencies] +tar = { version = "0.4" } + +[patch.crates-io] +russh = { git = "https://github.com/microsoft/vscode-russh", branch = "main" } +russh-cryptovec = { git = "https://github.com/microsoft/vscode-russh", branch = "main" } +russh-keys = { git = "https://github.com/microsoft/vscode-russh", branch = "main" } +secret-service = { git = "https://github.com/microsoft/vscode-secret-service-rs", rev = "30f0414108a122d6f2bfc28a5425d0dac9738518" } + +[profile.release] +strip = true +lto = true +codegen-units = 1 + +[features] +default = [] +vscode-encrypt = [] diff --git a/cli/build.rs b/cli/build.rs new file mode 100644 index 00000000000..797e612ec4b --- /dev/null +++ b/cli/build.rs @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const FILE_HEADER: &str = "/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/"; + +use std::{env, fs, io, path::PathBuf, process}; + +fn main() { + let files = enumerate_source_files().expect("expected to enumerate files"); + ensure_file_headers(&files).expect("expected to ensure file headers"); +} + +fn ensure_file_headers(files: &[PathBuf]) -> Result<(), io::Error> { + let mut ok = true; + + let crlf_header_str = str::replace(FILE_HEADER, "\n", "\r\n"); + let crlf_header = crlf_header_str.as_bytes(); + let lf_header = FILE_HEADER.as_bytes(); + for file in files { + let contents = fs::read(file)?; + + if !(contents.starts_with(lf_header) || contents.starts_with(crlf_header)) { + eprintln!("File missing copyright header: {}", file.display()); + ok = false; + } + } + + if !ok { + process::exit(1); + } + + Ok(()) +} + +/// Gets all "rs" files in the source directory +fn enumerate_source_files() -> Result, io::Error> { + let mut files = vec![]; + let mut queue = vec![]; + + let current_dir = env::current_dir()?.join("src"); + queue.push(current_dir); + + while !queue.is_empty() { + for entry in fs::read_dir(queue.pop().unwrap())? { + let entry = entry?; + let ftype = entry.file_type()?; + if ftype.is_dir() { + queue.push(entry.path()); + } else if ftype.is_file() && entry.file_name().to_string_lossy().ends_with(".rs") { + files.push(entry.path()); + } + } + } + + Ok(files) +} diff --git a/cli/rustfmt.toml b/cli/rustfmt.toml new file mode 100644 index 00000000000..218e203215e --- /dev/null +++ b/cli/rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/cli/src/auth.rs b/cli/src/auth.rs new file mode 100644 index 00000000000..55bc56c4817 --- /dev/null +++ b/cli/src/auth.rs @@ -0,0 +1,594 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use crate::{ + constants::get_default_user_agent, + info, log, + state::{LauncherPaths, PersistedState}, + trace, + util::{ + errors::{wrap, AnyError, RefreshTokenNotAvailableError, StatusError, WrappedError}, + input::prompt_options, + }, + warning, +}; +use async_trait::async_trait; +use chrono::{DateTime, Duration, Utc}; +use gethostname::gethostname; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use std::{cell::Cell, fmt::Display, path::PathBuf, sync::Arc}; +use tokio::time::sleep; +use tunnels::{ + contracts::PROD_FIRST_PARTY_APP_ID, + management::{Authorization, AuthorizationProvider, HttpError}, +}; + +#[derive(Deserialize)] +struct DeviceCodeResponse { + device_code: String, + user_code: String, + message: Option, + verification_uri: String, + expires_in: i64, +} + +#[derive(Deserialize)] +struct AuthenticationResponse { + access_token: String, + refresh_token: Option, + expires_in: Option, +} + +#[derive(clap::ArgEnum, Serialize, Deserialize, Debug, Clone, Copy)] +pub enum AuthProvider { + Microsoft, + Github, +} + +impl Display for AuthProvider { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AuthProvider::Microsoft => write!(f, "Microsoft Account"), + AuthProvider::Github => write!(f, "Github Account"), + } + } +} + +impl AuthProvider { + pub fn client_id(&self) -> &'static str { + match self { + AuthProvider::Microsoft => "aebc6443-996d-45c2-90f0-388ff96faa56", + AuthProvider::Github => "01ab8ac9400c4e429b23", + } + } + + pub fn code_uri(&self) -> &'static str { + match self { + AuthProvider::Microsoft => { + "https://login.microsoftonline.com/common/oauth2/v2.0/devicecode" + } + AuthProvider::Github => "https://github.com/login/device/code", + } + } + + pub fn grant_uri(&self) -> &'static str { + match self { + AuthProvider::Microsoft => "https://login.microsoftonline.com/common/oauth2/v2.0/token", + AuthProvider::Github => "https://github.com/login/oauth/access_token", + } + } + + pub fn get_default_scopes(&self) -> String { + match self { + AuthProvider::Microsoft => format!( + "{}/.default+offline_access+profile+openid", + PROD_FIRST_PARTY_APP_ID + ), + AuthProvider::Github => "read:user+read:org".to_string(), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct StoredCredential { + #[serde(rename = "p")] + provider: AuthProvider, + #[serde(rename = "a")] + access_token: String, + #[serde(rename = "r")] + refresh_token: Option, + #[serde(rename = "e")] + expires_at: Option>, +} + +impl StoredCredential { + pub async fn is_expired(&self, client: &reqwest::Client) -> bool { + match self.provider { + AuthProvider::Microsoft => self + .expires_at + .map(|e| Utc::now() + chrono::Duration::minutes(5) > e) + .unwrap_or(false), + + // Make an auth request to Github. Mark the credential as expired + // only on a verifiable 4xx code. We don't error on any failed + // request since then a drop in connection could "require" a refresh + AuthProvider::Github => client + .get("https://api.github.com/user") + .header("Authorization", format!("token {}", self.access_token)) + .header("User-Agent", get_default_user_agent()) + .send() + .await + .map(|r| r.status().is_client_error()) + .unwrap_or(false), + } + } + + fn from_response(auth: AuthenticationResponse, provider: AuthProvider) -> Self { + StoredCredential { + provider, + access_token: auth.access_token, + refresh_token: auth.refresh_token, + expires_at: auth.expires_in.map(|e| Utc::now() + Duration::seconds(e)), + } + } +} + +struct StorageWithLastRead { + storage: Box, + last_read: Cell, WrappedError>>, +} + +#[derive(Clone)] +pub struct Auth { + client: reqwest::Client, + log: log::Logger, + file_storage_path: PathBuf, + storage: Arc>>, +} + +trait StorageImplementation: Send + Sync { + fn read(&mut self) -> Result, WrappedError>; + fn store(&mut self, value: StoredCredential) -> Result<(), WrappedError>; + fn clear(&mut self) -> Result<(), WrappedError>; +} + +// unseal decrypts and deserializes the value +fn seal(value: &T) -> String +where + T: Serialize + ?Sized, +{ + let dec = serde_json::to_string(value).expect("expected to serialize"); + encrypt(&dec) +} + +// unseal decrypts and deserializes the value +fn unseal(value: &str) -> Option +where + T: DeserializeOwned, +{ + // small back-compat for old unencrypted values + if let Ok(v) = serde_json::from_str::(value) { + return Some(v); + } + + let dec = decrypt(value)?; + serde_json::from_str::(&dec).ok() +} + +#[cfg(target_os = "windows")] +const KEYCHAIN_ENTRY_LIMIT: usize = 1024; +#[cfg(not(target_os = "windows"))] +const KEYCHAIN_ENTRY_LIMIT: usize = 128 * 1024; + +const CONTINUE_MARKER: &str = ""; + +#[derive(Default)] +struct KeyringStorage { + // keywring storage can be split into multiple entries due to entry length limits + // on Windows https://github.com/microsoft/vscode-cli/issues/358 + entries: Vec, +} + +macro_rules! get_next_entry { + ($self: expr, $i: expr) => { + match $self.entries.get($i) { + Some(e) => e, + None => { + let e = keyring::Entry::new("vscode-cli", &format!("vscode-cli-{}", $i)); + $self.entries.push(e); + $self.entries.last().unwrap() + } + } + }; +} + +impl StorageImplementation for KeyringStorage { + fn read(&mut self) -> Result, WrappedError> { + let mut str = String::new(); + + for i in 0.. { + let entry = get_next_entry!(self, i); + let next_chunk = match entry.get_password() { + Ok(value) => value, + Err(keyring::Error::NoEntry) => return Ok(None), // missing entries? + Err(e) => return Err(wrap(e, "error reading keyring")), + }; + + if next_chunk.ends_with(CONTINUE_MARKER) { + str.push_str(&next_chunk[..next_chunk.len() - CONTINUE_MARKER.len()]); + } else { + str.push_str(&next_chunk); + break; + } + } + + Ok(unseal(&str)) + } + + fn store(&mut self, value: StoredCredential) -> Result<(), WrappedError> { + let sealed = seal(&value); + let step_size = KEYCHAIN_ENTRY_LIMIT - CONTINUE_MARKER.len(); + + for i in (0..sealed.len()).step_by(step_size) { + let entry = get_next_entry!(self, i / step_size); + + let cutoff = i + step_size; + let stored = if cutoff <= sealed.len() { + let mut part = sealed[i..cutoff].to_string(); + part.push_str(CONTINUE_MARKER); + entry.set_password(&part) + } else { + entry.set_password(&sealed[i..]) + }; + + if let Err(e) = stored { + return Err(wrap(e, "error updating keyring")); + } + } + + Ok(()) + } + + fn clear(&mut self) -> Result<(), WrappedError> { + self.read().ok(); // make sure component parts are available + for entry in self.entries.iter() { + entry + .delete_password() + .map_err(|e| wrap(e, "error updating keyring"))?; + } + self.entries.clear(); + + Ok(()) + } +} + +struct FileStorage(PersistedState>); + +impl StorageImplementation for FileStorage { + fn read(&mut self) -> Result, WrappedError> { + Ok(self.0.load().and_then(|s| unseal(&s))) + } + + fn store(&mut self, value: StoredCredential) -> Result<(), WrappedError> { + self.0.save(Some(seal(&value))) + } + + fn clear(&mut self) -> Result<(), WrappedError> { + self.0.save(None) + } +} + +impl Auth { + pub fn new(paths: &LauncherPaths, log: log::Logger) -> Auth { + Auth { + log, + client: reqwest::Client::new(), + file_storage_path: paths.root().join("token.json"), + storage: Arc::new(std::sync::Mutex::new(None)), + } + } + + fn with_storage(&self, op: F) -> T + where + F: FnOnce(&mut StorageWithLastRead) -> T, + { + let mut opt = self.storage.lock().unwrap(); + if let Some(s) = opt.as_mut() { + return op(s); + } + + let mut keyring_storage = KeyringStorage::default(); + let mut file_storage = FileStorage(PersistedState::new(self.file_storage_path.clone())); + + let keyring_storage_result = match std::env::var("VSCODE_CLI_USE_FILE_KEYCHAIN") { + Ok(_) => Err(wrap("", "user prefers file storage")), + _ => keyring_storage.read(), + }; + + let mut storage = match keyring_storage_result { + Ok(v) => StorageWithLastRead { + last_read: Cell::new(Ok(v)), + storage: Box::new(keyring_storage), + }, + Err(_) => StorageWithLastRead { + last_read: Cell::new(file_storage.read()), + storage: Box::new(file_storage), + }, + }; + + let out = op(&mut storage); + *opt = Some(storage); + out + } + + /// Gets a tunnel Authentication for use in the tunnel management API. + pub async fn get_tunnel_authentication(&self) -> Result { + let cred = self.get_credential().await?; + let auth = match cred.provider { + AuthProvider::Microsoft => Authorization::Bearer(cred.access_token), + AuthProvider::Github => Authorization::Github(format!( + "client_id={} {}", + cred.provider.client_id(), + cred.access_token + )), + }; + + Ok(auth) + } + + /// Reads the current details from the keyring. + pub fn get_current_credential(&self) -> Result, WrappedError> { + self.with_storage(|storage| { + let value = storage.last_read.replace(Ok(None)); + storage.last_read.set(value.clone()); + value + }) + } + + /// Clears login info from the keyring. + pub fn clear_credentials(&self) -> Result<(), WrappedError> { + self.with_storage(|storage| { + storage.storage.clear()?; + storage.last_read.set(Ok(None)); + Ok(()) + }) + } + + /// Runs the login flow, optionally pre-filling a provider and/or access token. + pub async fn login( + &self, + provider: Option, + access_token: Option, + ) -> Result { + let provider = match provider { + Some(p) => p, + None => self.prompt_for_provider().await?, + }; + + let credentials = match access_token { + Some(t) => StoredCredential { + provider, + access_token: t, + refresh_token: None, + expires_at: None, + }, + None => self.do_device_code_flow_with_provider(provider).await?, + }; + + self.store_credentials(credentials.clone()); + Ok(credentials) + } + + /// Gets the currently stored credentials, or asks the user to log in. + pub async fn get_credential(&self) -> Result { + let entry = match self.get_current_credential() { + Ok(Some(old_creds)) => { + trace!(self.log, "Found token in keyring"); + match self.get_refreshed_token(&old_creds).await { + Ok(Some(new_creds)) => { + self.store_credentials(new_creds.clone()); + new_creds + } + Ok(None) => old_creds, + Err(e) => { + info!(self.log, "error refreshing token: {}", e); + let new_creds = self + .do_device_code_flow_with_provider(old_creds.provider) + .await?; + self.store_credentials(new_creds.clone()); + new_creds + } + } + } + + Ok(None) => { + trace!(self.log, "No token in keyring, getting a new one"); + let creds = self.do_device_code_flow().await?; + self.store_credentials(creds.clone()); + creds + } + + Err(e) => { + warning!( + self.log, + "Error reading token from keyring, getting a new one: {}", + e + ); + let creds = self.do_device_code_flow().await?; + self.store_credentials(creds.clone()); + creds + } + }; + + Ok(entry) + } + + /// Stores credentials, logging a warning if it fails. + fn store_credentials(&self, creds: StoredCredential) { + self.with_storage(|storage| { + if let Err(e) = storage.storage.store(creds.clone()) { + warning!( + self.log, + "Failed to update keyring with new credentials: {}", + e + ); + } + storage.last_read.set(Ok(Some(creds))); + }) + } + + /// Refreshes the token in the credentials if necessary. Returns None if + /// the token is up to date, or Some new token otherwise. + async fn get_refreshed_token( + &self, + creds: &StoredCredential, + ) -> Result, AnyError> { + if !creds.is_expired(&self.client).await { + return Ok(None); + } + + let refresh_token = match &creds.refresh_token { + Some(t) => t, + None => return Err(AnyError::from(RefreshTokenNotAvailableError())), + }; + + self.do_grant( + creds.provider, + format!( + "client_id={}&grant_type=refresh_token&refresh_token={}", + creds.provider.client_id(), + refresh_token + ), + ) + .await + .map(Some) + } + + /// Does a "grant token" request. + async fn do_grant( + &self, + provider: AuthProvider, + body: String, + ) -> Result { + let response = self + .client + .post(provider.grant_uri()) + .body(body) + .header("Accept", "application/json") + .send() + .await?; + + if !response.status().is_success() { + return Err(StatusError::from_res(response).await?.into()); + } + + let body = response.json::().await?; + Ok(StoredCredential::from_response(body, provider)) + } + + /// Implements the device code flow, returning the credentials upon success. + async fn do_device_code_flow(&self) -> Result { + let provider = self.prompt_for_provider().await?; + self.do_device_code_flow_with_provider(provider).await + } + + async fn prompt_for_provider(&self) -> Result { + if std::env::var("VSCODE_CLI_ALLOW_MS_AUTH").is_err() { + return Ok(AuthProvider::Github); + } + + let provider = prompt_options( + "How would you like to log in to VS Code?", + &[AuthProvider::Microsoft, AuthProvider::Github], + )?; + + Ok(provider) + } + + async fn do_device_code_flow_with_provider( + &self, + provider: AuthProvider, + ) -> Result { + loop { + let init_code = self + .client + .post(provider.code_uri()) + .header("Accept", "application/json") + .body(format!( + "client_id={}&scope={}", + provider.client_id(), + provider.get_default_scopes(), + )) + .send() + .await?; + + if !init_code.status().is_success() { + return Err(StatusError::from_res(init_code).await?.into()); + } + + let init_code_json = init_code.json::().await?; + let expires_at = Utc::now() + chrono::Duration::seconds(init_code_json.expires_in); + + match &init_code_json.message { + Some(m) => self.log.result(m), + None => self.log.result(&format!( + "To grant access to the server, please log into {} and use code {}", + init_code_json.verification_uri, init_code_json.user_code + )), + }; + + let body = format!( + "client_id={}&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code={}", + provider.client_id(), + init_code_json.device_code + ); + + while Utc::now() < expires_at { + sleep(std::time::Duration::from_secs(5)).await; + + match self.do_grant(provider, body.clone()).await { + Ok(creds) => return Ok(creds), + Err(e) => { + trace!(self.log, "refresh poll failed, retrying: {}", e); + } + } + } + } + } +} + +#[async_trait] +impl AuthorizationProvider for Auth { + async fn get_authorization(&self) -> Result { + self.get_tunnel_authentication() + .await + .map_err(|e| HttpError::AuthorizationError(e.to_string())) + } +} + +lazy_static::lazy_static! { + static ref HOSTNAME: Vec = gethostname().to_string_lossy().bytes().collect(); +} + +#[cfg(feature = "vscode-encrypt")] +fn encrypt(value: &str) -> String { + vscode_encrypt::encrypt(&HOSTNAME, value.as_bytes()).expect("expected to encrypt") +} + +#[cfg(feature = "vscode-encrypt")] +fn decrypt(value: &str) -> Option { + let b = vscode_encrypt::decrypt(&HOSTNAME, value).ok()?; + String::from_utf8(b).ok() +} + +#[cfg(not(feature = "vscode-encrypt"))] +fn encrypt(value: &str) -> String { + value.to_owned() +} + +#[cfg(not(feature = "vscode-encrypt"))] +fn decrypt(value: &str) -> Option { + Some(value.to_owned()) +} diff --git a/cli/src/bin/code/legacy_args.rs b/cli/src/bin/code/legacy_args.rs new file mode 100644 index 00000000000..361348d8373 --- /dev/null +++ b/cli/src/bin/code/legacy_args.rs @@ -0,0 +1,234 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::collections::HashMap; + +use cli::commands::args::{ + CliCore, Commands, DesktopCodeOptions, ExtensionArgs, ExtensionSubcommand, + InstallExtensionArgs, ListExtensionArgs, UninstallExtensionArgs, +}; + +/// Tries to parse the argv using the legacy CLI interface, looking for its +/// flags and generating a CLI with subcommands if those don't exist. +pub fn try_parse_legacy( + iter: impl IntoIterator>, +) -> Option { + let raw = clap_lex::RawArgs::new(iter); + let mut cursor = raw.cursor(); + raw.next(&mut cursor); // Skip the bin + + // First make a hashmap of all flags and capture positional arguments. + let mut args: HashMap> = HashMap::new(); + let mut last_arg = None; + while let Some(arg) = raw.next(&mut cursor) { + if let Some((long, value)) = arg.to_long() { + if let Ok(long) = long { + last_arg = Some(long.to_string()); + match args.get_mut(long) { + Some(prev) => { + if let Some(v) = value { + prev.push(v.to_str_lossy().to_string()); + } + } + None => { + if let Some(v) = value { + args.insert(long.to_string(), vec![v.to_str_lossy().to_string()]); + } else { + args.insert(long.to_string(), vec![]); + } + } + } + } + } else if let Ok(value) = arg.to_value() { + if let Some(last_arg) = &last_arg { + args.get_mut(last_arg) + .expect("expected to have last arg") + .push(value.to_string()); + } + } + } + + let get_first_arg_value = + |key: &str| args.get(key).and_then(|v| v.first()).map(|s| s.to_string()); + let desktop_code_options = DesktopCodeOptions { + extensions_dir: get_first_arg_value("extensions-dir"), + user_data_dir: get_first_arg_value("user-data-dir"), + use_version: None, + }; + + // Now translate them to subcommands. + // --list-extensions -> ext list + // --install-extension=id -> ext install + // --uninstall-extension=id -> ext uninstall + // --status -> status + + if args.contains_key("list-extensions") { + Some(CliCore { + subcommand: Some(Commands::Extension(ExtensionArgs { + subcommand: ExtensionSubcommand::List(ListExtensionArgs { + category: get_first_arg_value("category"), + show_versions: args.contains_key("show-versions"), + }), + desktop_code_options, + })), + ..Default::default() + }) + } else if let Some(exts) = args.remove("install-extension") { + Some(CliCore { + subcommand: Some(Commands::Extension(ExtensionArgs { + subcommand: ExtensionSubcommand::Install(InstallExtensionArgs { + id_or_path: exts, + pre_release: args.contains_key("pre-release"), + force: args.contains_key("force"), + }), + desktop_code_options, + })), + ..Default::default() + }) + } else if let Some(exts) = args.remove("uninstall-extension") { + Some(CliCore { + subcommand: Some(Commands::Extension(ExtensionArgs { + subcommand: ExtensionSubcommand::Uninstall(UninstallExtensionArgs { id: exts }), + desktop_code_options, + })), + ..Default::default() + }) + } else if args.contains_key("status") { + Some(CliCore { + subcommand: Some(Commands::Status), + ..Default::default() + }) + } else { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parses_list_extensions() { + let args = vec![ + "code", + "--list-extensions", + "--category", + "themes", + "--show-versions", + ]; + let cli = try_parse_legacy(args.into_iter()).unwrap(); + + if let Some(Commands::Extension(extension_args)) = cli.subcommand { + if let ExtensionSubcommand::List(list_args) = extension_args.subcommand { + assert_eq!(list_args.category, Some("themes".to_string())); + assert!(list_args.show_versions); + } else { + panic!( + "Expected list subcommand, got {:?}", + extension_args.subcommand + ); + } + } else { + panic!("Expected extension subcommand, got {:?}", cli.subcommand); + } + } + + #[test] + fn test_parses_install_extension() { + let args = vec![ + "code", + "--install-extension", + "connor4312.codesong", + "connor4312.hello-world", + "--pre-release", + "--force", + ]; + let cli = try_parse_legacy(args.into_iter()).unwrap(); + + if let Some(Commands::Extension(extension_args)) = cli.subcommand { + if let ExtensionSubcommand::Install(install_args) = extension_args.subcommand { + assert_eq!( + install_args.id_or_path, + vec!["connor4312.codesong", "connor4312.hello-world"] + ); + assert!(install_args.pre_release); + assert!(install_args.force); + } else { + panic!( + "Expected install subcommand, got {:?}", + extension_args.subcommand + ); + } + } else { + panic!("Expected extension subcommand, got {:?}", cli.subcommand); + } + } + + #[test] + fn test_parses_uninstall_extension() { + let args = vec!["code", "--uninstall-extension", "connor4312.codesong"]; + let cli = try_parse_legacy(args.into_iter()).unwrap(); + + if let Some(Commands::Extension(extension_args)) = cli.subcommand { + if let ExtensionSubcommand::Uninstall(uninstall_args) = extension_args.subcommand { + assert_eq!(uninstall_args.id, vec!["connor4312.codesong"]); + } else { + panic!( + "Expected uninstall subcommand, got {:?}", + extension_args.subcommand + ); + } + } else { + panic!("Expected extension subcommand, got {:?}", cli.subcommand); + } + } + + #[test] + fn test_parses_user_data_dir_and_extensions_dir() { + let args = vec![ + "code", + "--uninstall-extension", + "connor4312.codesong", + "--user-data-dir", + "foo", + "--extensions-dir", + "bar", + ]; + let cli = try_parse_legacy(args.into_iter()).unwrap(); + + if let Some(Commands::Extension(extension_args)) = cli.subcommand { + assert_eq!( + extension_args.desktop_code_options.user_data_dir, + Some("foo".to_string()) + ); + assert_eq!( + extension_args.desktop_code_options.extensions_dir, + Some("bar".to_string()) + ); + if let ExtensionSubcommand::Uninstall(uninstall_args) = extension_args.subcommand { + assert_eq!(uninstall_args.id, vec!["connor4312.codesong"]); + } else { + panic!( + "Expected uninstall subcommand, got {:?}", + extension_args.subcommand + ); + } + } else { + panic!("Expected extension subcommand, got {:?}", cli.subcommand); + } + } + + #[test] + fn test_status() { + let args = vec!["code", "--status"]; + let cli = try_parse_legacy(args.into_iter()).unwrap(); + + if let Some(Commands::Status) = cli.subcommand { + // no-op + } else { + panic!("Expected extension subcommand, got {:?}", cli.subcommand); + } + } +} diff --git a/cli/src/bin/code/main.rs b/cli/src/bin/code/main.rs new file mode 100644 index 00000000000..ce98c0faaf4 --- /dev/null +++ b/cli/src/bin/code/main.rs @@ -0,0 +1,186 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +mod legacy_args; + +use std::process::Command; + +use clap::Parser; +use cli::{ + commands::{args, tunnels, update, version, CommandContext}, + desktop, log as own_log, + state::LauncherPaths, + util::{ + errors::{wrap, AnyError}, + is_integrated_cli, + prereqs::PreReqChecker, + }, +}; +use legacy_args::try_parse_legacy; +use opentelemetry::sdk::trace::TracerProvider as SdkTracerProvider; +use opentelemetry::trace::TracerProvider; + +use log::{Level, Metadata, Record}; + +#[tokio::main] +async fn main() -> Result<(), std::convert::Infallible> { + let raw_args = std::env::args_os().collect::>(); + let parsed = try_parse_legacy(&raw_args) + .map(|core| args::AnyCli::Integrated(args::IntegratedCli { core })) + .unwrap_or_else(|| { + if let Ok(true) = is_integrated_cli() { + args::AnyCli::Integrated(args::IntegratedCli::parse_from(&raw_args)) + } else { + args::AnyCli::Standalone(args::StandaloneCli::parse_from(&raw_args)) + } + }); + + let core = parsed.core(); + let context = CommandContext { + http: reqwest::Client::new(), + paths: LauncherPaths::new(&core.global_options.cli_data_dir).unwrap(), + log: own_log::Logger::new( + SdkTracerProvider::builder().build().tracer("codecli"), + if core.global_options.verbose { + own_log::Level::Trace + } else { + core.global_options.log.unwrap_or(own_log::Level::Info) + }, + ), + args: core.clone(), + }; + + log::set_logger(Box::leak(Box::new(RustyLogger(context.log.clone())))) + .map(|()| log::set_max_level(log::LevelFilter::Debug)) + .expect("expected to make logger"); + + let result = match parsed { + args::AnyCli::Standalone(args::StandaloneCli { + subcommand: Some(cmd), + .. + }) => match cmd { + args::StandaloneCommands::Update(args) => update::update(context, args).await, + }, + args::AnyCli::Standalone(args::StandaloneCli { core: c, .. }) + | args::AnyCli::Integrated(args::IntegratedCli { core: c, .. }) => match c.subcommand { + None => { + let ca = context.args.get_base_code_args(); + start_code(context, ca).await + } + + Some(args::Commands::Extension(extension_args)) => { + let mut ca = context.args.get_base_code_args(); + extension_args.add_code_args(&mut ca); + start_code(context, ca).await + } + + Some(args::Commands::Status) => { + let mut ca = context.args.get_base_code_args(); + ca.push("--status".to_string()); + start_code(context, ca).await + } + + Some(args::Commands::Version(version_args)) => match version_args.subcommand { + args::VersionSubcommand::Use(use_version_args) => { + version::switch_to(context, use_version_args).await + } + args::VersionSubcommand::Show => version::show(context).await, + }, + + Some(args::Commands::Tunnel(tunnel_args)) => match tunnel_args.subcommand { + Some(args::TunnelSubcommand::Prune) => tunnels::prune(context).await, + Some(args::TunnelSubcommand::Unregister) => tunnels::unregister(context).await, + Some(args::TunnelSubcommand::Rename(rename_args)) => { + tunnels::rename(context, rename_args).await + } + Some(args::TunnelSubcommand::User(user_command)) => { + tunnels::user(context, user_command).await + } + Some(args::TunnelSubcommand::Service(service_args)) => { + tunnels::service(context, service_args).await + } + None => tunnels::serve(context, tunnel_args.serve_args).await, + }, + }, + }; + + match result { + Err(e) => print_and_exit(e), + Ok(code) => std::process::exit(code), + } +} + +fn print_and_exit(err: E) -> ! +where + E: std::fmt::Display, +{ + own_log::emit(own_log::Level::Error, "", &format!("{}", err)); + std::process::exit(1); +} + +async fn start_code(context: CommandContext, args: Vec) -> Result { + // todo: once the integrated CLI takes the place of the Node.js CLI, this should + // redirect to the current installation without using the CodeVersionManager. + + let platform = PreReqChecker::new().verify().await?; + let version_manager = + desktop::CodeVersionManager::new(context.log.clone(), &context.paths, platform); + let version = match &context.args.editor_options.code_options.use_version { + Some(v) => desktop::RequestedVersion::try_from(v.as_str())?, + None => version_manager.get_preferred_version(), + }; + + let binary = match version_manager.try_get_entrypoint(&version).await { + Some(ep) => ep, + None => { + desktop::prompt_to_install(&version); + return Ok(1); + } + }; + + let code = Command::new(&binary) + .args(args) + .status() + .map(|s| s.code().unwrap_or(1)) + .map_err(|e| wrap(e, format!("error running VS Code from {}", binary.display())))?; + + Ok(code) +} + +/// Logger that uses the common rust "log" crate and directs back to one of +/// our managed loggers. +struct RustyLogger(own_log::Logger); + +impl log::Log for RustyLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= Level::Debug + } + + fn log(&self, record: &Record) { + if !self.enabled(record.metadata()) { + return; + } + + // exclude noisy log modules: + let src = match record.module_path() { + Some("russh::cipher") => return, + Some("russh::negotiation") => return, + Some(s) => s, + None => "", + }; + + self.0.emit( + match record.level() { + log::Level::Debug => own_log::Level::Debug, + log::Level::Error => own_log::Level::Error, + log::Level::Info => own_log::Level::Info, + log::Level::Trace => own_log::Level::Trace, + log::Level::Warn => own_log::Level::Warn, + }, + &format!("[{}] {}", src, record.args()), + ); + } + + fn flush(&self) {} +} diff --git a/cli/src/commands.rs b/cli/src/commands.rs new file mode 100644 index 00000000000..754729f2c04 --- /dev/null +++ b/cli/src/commands.rs @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +mod context; + +pub mod args; +pub mod tunnels; +pub mod update; +pub mod version; +pub use context::CommandContext; diff --git a/cli/src/commands/args.rs b/cli/src/commands/args.rs new file mode 100644 index 00000000000..d2fdeaae822 --- /dev/null +++ b/cli/src/commands/args.rs @@ -0,0 +1,638 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::fmt; + +use crate::{constants, log, options, tunnels::code_server::CodeServerArgs}; +use clap::{ArgEnum, Args, Parser, Subcommand}; + +const TEMPLATE: &str = " + Visual Studio Code CLI - {version} + + Usage: code-insiders.exe [options][paths...] + + To read output from another program, append '-' (e.g. 'echo Hello World | code-insiders.exe -') + + {all-args}"; + +#[derive(Parser, Debug, Default)] +#[clap( + help_template = TEMPLATE, + long_about = None, + name = "Visual Studio Code CLI", + version = match constants::VSCODE_CLI_VERSION { Some(v) => v, None => "dev" }, + )] +pub struct IntegratedCli { + #[clap(flatten)] + pub core: CliCore, +} + +/// Common CLI shared between intergated and standalone interfaces. +#[derive(Args, Debug, Default, Clone)] +pub struct CliCore { + /// One or more files, folders, or URIs to open. + #[clap(name = "paths")] + pub open_paths: Vec, + + #[clap(flatten, next_help_heading = Some("EDITOR OPTIONS"))] + pub editor_options: EditorOptions, + + #[clap(flatten, next_help_heading = Some("EDITOR TROUBLESHOOTING"))] + pub troubleshooting: EditorTroubleshooting, + + #[clap(flatten, next_help_heading = Some("GLOBAL OPTIONS"))] + pub global_options: GlobalOptions, + + #[clap(subcommand)] + pub subcommand: Option, +} + +#[derive(Parser, Debug, Default)] +#[clap( + help_template = TEMPLATE, + long_about = None, + name = "Visual Studio Code CLI", + version = match constants::VSCODE_CLI_VERSION { Some(v) => v, None => "dev" }, + )] +pub struct StandaloneCli { + #[clap(flatten)] + pub core: CliCore, + + #[clap(subcommand)] + pub subcommand: Option, +} + +pub enum AnyCli { + Integrated(IntegratedCli), + Standalone(StandaloneCli), +} + +impl AnyCli { + pub fn core(&self) -> &CliCore { + match self { + AnyCli::Integrated(cli) => &cli.core, + AnyCli::Standalone(cli) => &cli.core, + } + } +} + +impl CliCore { + pub fn get_base_code_args(&self) -> Vec { + let mut args = self.open_paths.clone(); + self.editor_options.add_code_args(&mut args); + self.troubleshooting.add_code_args(&mut args); + self.global_options.add_code_args(&mut args); + args + } +} + +impl<'a> From<&'a CliCore> for CodeServerArgs { + fn from(cli: &'a CliCore) -> Self { + let mut args = CodeServerArgs { + log: cli.global_options.log, + accept_server_license_terms: true, + ..Default::default() + }; + + args.log = cli.global_options.log; + args.accept_server_license_terms = true; + + if cli.global_options.verbose { + args.verbose = true; + } + + if cli.global_options.disable_telemetry { + args.telemetry_level = Some(options::TelemetryLevel::Off); + } else if cli.global_options.telemetry_level.is_some() { + args.telemetry_level = cli.global_options.telemetry_level; + } + + args + } +} + +#[derive(Subcommand, Debug, Clone)] +pub enum StandaloneCommands { + /// Updates the VS Code CLI. + Update(StandaloneUpdateArgs), +} + +#[derive(Args, Debug, Clone)] +pub struct StandaloneUpdateArgs { + /// Only check for updates, without actually updating the CLI. + #[clap(long)] + pub check: bool, +} + +#[derive(Subcommand, Debug, Clone)] + +pub enum Commands { + /// Create a tunnel that's accessible on vscode.dev from anywhere. + /// Run `code tunnel --help` for more usage info. + Tunnel(TunnelArgs), + + /// Manage VS Code extensions. + #[clap(name = "ext")] + Extension(ExtensionArgs), + + /// Print process usage and diagnostics information. + Status, + + /// Changes the version of VS Code you're using. + Version(VersionArgs), +} + +#[derive(Args, Debug, Clone)] +pub struct ExtensionArgs { + #[clap(subcommand)] + pub subcommand: ExtensionSubcommand, + + #[clap(flatten)] + pub desktop_code_options: DesktopCodeOptions, +} + +impl ExtensionArgs { + pub fn add_code_args(&self, target: &mut Vec) { + if let Some(ed) = &self.desktop_code_options.extensions_dir { + target.push(ed.to_string()); + } + + self.subcommand.add_code_args(target); + } +} + +#[derive(Subcommand, Debug, Clone)] +pub enum ExtensionSubcommand { + /// List installed extensions. + List(ListExtensionArgs), + /// Install an extension. + Install(InstallExtensionArgs), + /// Uninstall an extension. + Uninstall(UninstallExtensionArgs), +} + +impl ExtensionSubcommand { + pub fn add_code_args(&self, target: &mut Vec) { + match self { + ExtensionSubcommand::List(args) => { + target.push("--list-extensions".to_string()); + if args.show_versions { + target.push("--show-versions".to_string()); + } + if let Some(category) = &args.category { + target.push(format!("--category={}", category)); + } + } + ExtensionSubcommand::Install(args) => { + for id in args.id_or_path.iter() { + target.push(format!("--install-extension={}", id)); + } + if args.pre_release { + target.push("--pre-release".to_string()); + } + if args.force { + target.push("--force".to_string()); + } + } + ExtensionSubcommand::Uninstall(args) => { + for id in args.id.iter() { + target.push(format!("--uninstall-extension={}", id)); + } + } + } + } +} + +#[derive(Args, Debug, Clone)] +pub struct ListExtensionArgs { + /// Filters installed extensions by provided category, when using --list-extensions. + #[clap(long, value_name = "category")] + pub category: Option, + + /// Show versions of installed extensions, when using --list-extensions. + #[clap(long)] + pub show_versions: bool, +} + +#[derive(Args, Debug, Clone)] +pub struct InstallExtensionArgs { + /// Either an extension id or a path to a VSIX. The identifier of an + /// extension is '${publisher}.${name}'. Use '--force' argument to update + /// to latest version. To install a specific version provide '@${version}'. + /// For example: 'vscode.csharp@1.2.3'. + #[clap(name = "ext-id | id")] + pub id_or_path: Vec, + + /// Installs the pre-release version of the extension + #[clap(long)] + pub pre_release: bool, + + /// Update to the latest version of the extension if it's already installed. + #[clap(long)] + pub force: bool, +} + +#[derive(Args, Debug, Clone)] +pub struct UninstallExtensionArgs { + /// One or more extension identifiers to uninstall. The identifier of an + /// extension is '${publisher}.${name}'. Use '--force' argument to update + /// to latest version. + #[clap(name = "ext-id")] + pub id: Vec, +} + +#[derive(Args, Debug, Clone)] +pub struct VersionArgs { + #[clap(subcommand)] + pub subcommand: VersionSubcommand, +} + +#[derive(Subcommand, Debug, Clone)] +pub enum VersionSubcommand { + /// Switches the instance of VS Code in use. + Use(UseVersionArgs), + + /// Shows the currently configured VS Code version. + Show, +} + +#[derive(Args, Debug, Clone)] +pub struct UseVersionArgs { + /// The version of VS Code you want to use. Can be "stable", "insiders", + /// a version number, or an absolute path to an existing install. + #[clap(value_name = "stable | insiders | x.y.z | path")] + pub name: String, + + /// The directory where the version can be found. + #[clap(long, value_name = "path")] + pub install_dir: Option, +} + +#[derive(Args, Debug, Default, Clone)] +pub struct EditorOptions { + /// Compare two files with each other. + #[clap(short, long, value_names = &["file", "file"])] + pub diff: Vec, + + /// Add folder(s) to the last active window. + #[clap(short, long, value_name = "folder")] + pub add: Option, + + /// Open a file at the path on the specified line and character position. + #[clap(short, long, value_name = "file:line[:character]")] + pub goto: Option, + + /// Force to open a new window. + #[clap(short, long)] + pub new_window: bool, + + /// Force to open a file or folder in an + #[clap(short, long)] + pub reuse_window: bool, + + /// Wait for the files to be closed before returning. + #[clap(short, long)] + pub wait: bool, + + /// The locale to use (e.g. en-US or zh-TW). + #[clap(long, value_name = "locale")] + pub locale: Option, + + /// Enables proposed API features for extensions. Can receive one or + /// more extension IDs to enable individually. + #[clap(long, value_name = "ext-id")] + pub enable_proposed_api: Vec, + + #[clap(flatten)] + pub code_options: DesktopCodeOptions, +} + +impl EditorOptions { + pub fn add_code_args(&self, target: &mut Vec) { + if !self.diff.is_empty() { + target.push("--diff".to_string()); + for file in self.diff.iter() { + target.push(file.clone()); + } + } + if let Some(add) = &self.add { + target.push("--add".to_string()); + target.push(add.clone()); + } + if let Some(goto) = &self.goto { + target.push("--goto".to_string()); + target.push(goto.clone()); + } + if self.new_window { + target.push("--new-window".to_string()); + } + if self.reuse_window { + target.push("--reuse-window".to_string()); + } + if self.wait { + target.push("--wait".to_string()); + } + if let Some(locale) = &self.locale { + target.push(format!("--locale={}", locale)); + } + if !self.enable_proposed_api.is_empty() { + for id in self.enable_proposed_api.iter() { + target.push(format!("--enable-proposed-api={}", id)); + } + } + self.code_options.add_code_args(target); + } +} + +/// Arguments applicable whenever VS Code desktop is launched +#[derive(Args, Debug, Default, Clone)] +pub struct DesktopCodeOptions { + /// Set the root path for extensions. + #[clap(long, value_name = "dir")] + pub extensions_dir: Option, + + /// Specifies the directory that user data is kept in. Can be used to + /// open multiple distinct instances of Code. + #[clap(long, value_name = "dir")] + pub user_data_dir: Option, + + /// Sets the VS Code version to use for this command. The preferred version + /// can be persisted with `code version use `. Can be "stable", + /// "insiders", a version number, or an absolute path to an existing install. + #[clap(long, value_name = "stable | insiders | x.y.z | path")] + pub use_version: Option, +} + +/// Argument specifying the output format. +#[derive(Args, Debug, Clone)] +pub struct OutputFormatOptions { + /// Set the data output formats. + #[clap(arg_enum, long, value_name = "format", default_value_t = OutputFormat::Text)] + pub format: OutputFormat, +} + +impl DesktopCodeOptions { + pub fn add_code_args(&self, target: &mut Vec) { + if let Some(extensions_dir) = &self.extensions_dir { + target.push(format!("--extensions-dir={}", extensions_dir)); + } + if let Some(user_data_dir) = &self.user_data_dir { + target.push(format!("--user-data-dir={}", user_data_dir)); + } + } +} + +#[derive(Args, Debug, Default, Clone)] +pub struct GlobalOptions { + /// Directory where CLI metadata, such as VS Code installations, should be stored. + #[clap(long, env = "VSCODE_CLI_DATA_DIR", global = true)] + pub cli_data_dir: Option, + + /// Print verbose output (implies --wait). + #[clap(long, global = true)] + pub verbose: bool, + + /// Log level to use. + #[clap(long, arg_enum, value_name = "level", global = true)] + pub log: Option, + + /// Disable telemetry for the current command, even if it was previously + /// accepted as part of the license prompt or specified in '--telemetry-level' + #[clap(long, global = true, hide = true)] + pub disable_telemetry: bool, + + /// Sets the initial telemetry level + #[clap(arg_enum, long, global = true, hide = true)] + pub telemetry_level: Option, +} + +impl GlobalOptions { + pub fn add_code_args(&self, target: &mut Vec) { + if self.verbose { + target.push("--verbose".to_string()); + } + if let Some(log) = self.log { + target.push(format!("--log={}", log)); + } + if self.disable_telemetry { + target.push("--disable-telemetry".to_string()); + } + if let Some(telemetry_level) = &self.telemetry_level { + target.push(format!("--telemetry-level={}", telemetry_level)); + } + } +} + +#[derive(Args, Debug, Default, Clone)] +pub struct EditorTroubleshooting { + /// Run CPU profiler during startup. + #[clap(long)] + pub prof_startup: bool, + + /// Disable all installed extensions. + #[clap(long)] + pub disable_extensions: bool, + + /// Disable an extension. + #[clap(long, value_name = "ext-id")] + pub disable_extension: Vec, + + /// Turn sync on or off. + #[clap(arg_enum, long, value_name = "on | off")] + pub sync: Option, + + /// Allow debugging and profiling of extensions. Check the developer tools for the connection URI. + #[clap(long, value_name = "port")] + pub inspect_extensions: Option, + + /// Allow debugging and profiling of extensions with the extension host + /// being paused after start. Check the developer tools for the connection URI. + #[clap(long, value_name = "port")] + pub inspect_brk_extensions: Option, + + /// Disable GPU hardware acceleration. + #[clap(long)] + pub disable_gpu: bool, + + /// Max memory size for a window (in Mbytes). + #[clap(long, value_name = "memory")] + pub max_memory: Option, + + /// Shows all telemetry events which VS code collects. + #[clap(long)] + pub telemetry: bool, +} + +impl EditorTroubleshooting { + pub fn add_code_args(&self, target: &mut Vec) { + if self.prof_startup { + target.push("--prof-startup".to_string()); + } + if self.disable_extensions { + target.push("--disable-extensions".to_string()); + } + for id in self.disable_extension.iter() { + target.push(format!("--disable-extension={}", id)); + } + if let Some(sync) = &self.sync { + target.push(format!("--sync={}", sync)); + } + if let Some(port) = &self.inspect_extensions { + target.push(format!("--inspect-extensions={}", port)); + } + if let Some(port) = &self.inspect_brk_extensions { + target.push(format!("--inspect-brk-extensions={}", port)); + } + if self.disable_gpu { + target.push("--disable-gpu".to_string()); + } + if let Some(memory) = &self.max_memory { + target.push(format!("--max-memory={}", memory)); + } + if self.telemetry { + target.push("--telemetry".to_string()); + } + } +} + +#[derive(ArgEnum, Clone, Copy, Debug)] +pub enum SyncState { + On, + Off, +} + +impl fmt::Display for SyncState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + SyncState::Off => write!(f, "off"), + SyncState::On => write!(f, "on"), + } + } +} + +#[derive(ArgEnum, Clone, Copy, Debug)] +pub enum OutputFormat { + Json, + Text, +} + +#[derive(Args, Clone, Debug, Default)] +pub struct ExistingTunnelArgs { + /// Name you'd like to assign preexisting tunnel to use to connect the tunnel + #[clap(long, hide = true)] + pub tunnel_name: Option, + + /// Token to authenticate and use preexisting tunnel + #[clap(long, hide = true)] + pub host_token: Option, + + /// ID of preexisting tunnel to use to connect the tunnel + #[clap(long, hide = true)] + pub tunnel_id: Option, + + /// Cluster of preexisting tunnel to use to connect the tunnel + #[clap(long, hide = true)] + pub cluster: Option, +} + +#[derive(Args, Debug, Clone, Default)] +pub struct TunnelServeArgs { + /// Optional details to connect to an existing tunnel + #[clap(flatten, next_help_heading = Some("ADVANCED OPTIONS"))] + pub tunnel: ExistingTunnelArgs, + + /// Randomly name machine for port forwarding service + #[clap(long)] + pub random_name: bool, + + /// Sets the machine name for port forwarding service + #[clap(long)] + pub name: Option, + + /// Optional parent process id. If provided, the server will be stopped when the process of the given pid no longer exists + #[clap(long, hide = true)] + pub parent_process_id: Option, + + /// If set, the user accepts the server license terms and the server will be started without a user prompt. + #[clap(long)] + pub accept_server_license_terms: bool, +} + +#[derive(Args, Debug, Clone)] +pub struct TunnelArgs { + #[clap(subcommand)] + pub subcommand: Option, + + #[clap(flatten)] + pub serve_args: TunnelServeArgs, +} + +#[derive(Subcommand, Debug, Clone)] +pub enum TunnelSubcommand { + /// Delete all servers which are currently not running. + Prune, + + /// Rename the name of this machine associated with port forwarding service. + Rename(TunnelRenameArgs), + + /// Remove this machine's association with the port forwarding service. + Unregister, + + #[clap(subcommand)] + User(TunnelUserSubCommands), + + /// Manages the tunnel when installed as a system service, + #[clap(subcommand)] + Service(TunnelServiceSubCommands), +} + +#[derive(Subcommand, Debug, Clone)] +pub enum TunnelServiceSubCommands { + /// Installs or re-installs the tunnel service on the machine. + Install, + + /// Uninstalls and stops the tunnel service. + Uninstall, + + /// Internal command for running the service + #[clap(hide = true)] + InternalRun, +} + +#[derive(Args, Debug, Clone)] +pub struct TunnelRenameArgs { + /// The name you'd like to rename your machine to. + pub name: String, +} + +#[derive(Subcommand, Debug, Clone)] +pub enum TunnelUserSubCommands { + /// Log in to port forwarding service + Login(LoginArgs), + + /// Log out of port forwarding service + Logout, + + /// Show the account that's logged into port forwarding service + Show, +} + +#[derive(Args, Debug, Clone)] +pub struct LoginArgs { + /// An access token to store for authentication. Note: this will not be + /// refreshed if it expires! + #[clap(long, requires = "provider")] + pub access_token: Option, + + /// The auth provider to use. If not provided, a prompt will be shown. + #[clap(arg_enum, long)] + pub provider: Option, +} + +#[derive(clap::ArgEnum, Debug, Clone, Copy)] +pub enum AuthProvider { + Microsoft, + Github, +} diff --git a/cli/src/commands/context.rs b/cli/src/commands/context.rs new file mode 100644 index 00000000000..630d0bb028b --- /dev/null +++ b/cli/src/commands/context.rs @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use crate::{log, state::LauncherPaths}; + +use super::args::CliCore; + +pub struct CommandContext { + pub log: log::Logger, + pub paths: LauncherPaths, + pub args: CliCore, + pub http: reqwest::Client, +} diff --git a/cli/src/commands/output.rs b/cli/src/commands/output.rs new file mode 100644 index 00000000000..8747457889b --- /dev/null +++ b/cli/src/commands/output.rs @@ -0,0 +1,135 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::fmt::Display; + +use std::io::{BufWriter, Write}; + +use super::args::OutputFormat; + +pub struct Column { + max_width: usize, + heading: &'static str, + data: Vec, +} + +impl Column { + pub fn new(heading: &'static str) -> Self { + Column { + max_width: heading.len(), + heading, + data: vec![], + } + } + + pub fn add_row(&mut self, row: String) { + self.max_width = std::cmp::max(self.max_width, row.len()); + self.data.push(row); + } +} + +impl OutputFormat { + pub fn print_table(&self, table: OutputTable) -> Result<(), std::io::Error> { + match *self { + OutputFormat::Json => JsonTablePrinter().print(table, &mut std::io::stdout()), + OutputFormat::Text => TextTablePrinter().print(table, &mut std::io::stdout()), + } + } +} + +pub struct OutputTable { + cols: Vec, +} + +impl OutputTable { + pub fn new(cols: Vec) -> Self { + OutputTable { cols } + } +} + +trait TablePrinter { + fn print(&self, table: OutputTable, out: &mut dyn std::io::Write) + -> Result<(), std::io::Error>; +} + +pub struct JsonTablePrinter(); + +impl TablePrinter for JsonTablePrinter { + fn print( + &self, + table: OutputTable, + out: &mut dyn std::io::Write, + ) -> Result<(), std::io::Error> { + let mut bw = BufWriter::new(out); + bw.write_all(b"[")?; + + if !table.cols.is_empty() { + let data_len = table.cols[0].data.len(); + for i in 0..data_len { + if i > 0 { + bw.write_all(b",{")?; + } else { + bw.write_all(b"{")?; + } + for col in &table.cols { + serde_json::to_writer(&mut bw, col.heading)?; + bw.write_all(b":")?; + serde_json::to_writer(&mut bw, &col.data[i])?; + } + } + } + + bw.write_all(b"]")?; + bw.flush() + } +} + +/// Type that prints the output as an ASCII, markdown-style table. +pub struct TextTablePrinter(); + +impl TablePrinter for TextTablePrinter { + fn print( + &self, + table: OutputTable, + out: &mut dyn std::io::Write, + ) -> Result<(), std::io::Error> { + let mut bw = BufWriter::new(out); + + let sizes = table.cols.iter().map(|c| c.max_width).collect::>(); + + // print headers + write_columns(&mut bw, table.cols.iter().map(|c| c.heading), &sizes)?; + // print --- separators + write_columns( + &mut bw, + table.cols.iter().map(|c| "-".repeat(c.max_width)), + &sizes, + )?; + // print each column + if !table.cols.is_empty() { + let data_len = table.cols[0].data.len(); + for i in 0..data_len { + write_columns(&mut bw, table.cols.iter().map(|c| &c.data[i]), &sizes)?; + } + } + + bw.flush() + } +} + +fn write_columns( + mut w: impl Write, + cols: impl Iterator, + sizes: &[usize], +) -> Result<(), std::io::Error> +where + T: Display, +{ + w.write_all(b"|")?; + for (i, col) in cols.enumerate() { + write!(w, " {:width$} |", col, width = sizes[i])?; + } + w.write_all(b"\r\n") +} diff --git a/cli/src/commands/tunnels.rs b/cli/src/commands/tunnels.rs new file mode 100644 index 00000000000..0dea7761d93 --- /dev/null +++ b/cli/src/commands/tunnels.rs @@ -0,0 +1,299 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use async_trait::async_trait; +use std::str::FromStr; +use std::fmt; +use sysinfo::{Pid, SystemExt}; +use tokio::sync::mpsc; +use tokio::time::{sleep, Duration}; + +use super::{ + args::{ + AuthProvider, CliCore, ExistingTunnelArgs, TunnelRenameArgs, TunnelServeArgs, + TunnelServiceSubCommands, TunnelUserSubCommands, + }, + CommandContext, +}; + +use crate::{ + auth::Auth, + log::{self, Logger}, + state::LauncherPaths, + tunnels::{ + code_server::CodeServerArgs, create_service_manager, dev_tunnels, legal, + paths::get_all_servers, ServiceContainer, ServiceManager, + }, + util::{ + errors::{wrap, AnyError}, + prereqs::PreReqChecker, + }, +}; + +impl From for crate::auth::AuthProvider { + fn from(auth_provider: AuthProvider) -> Self { + match auth_provider { + AuthProvider::Github => crate::auth::AuthProvider::Github, + AuthProvider::Microsoft => crate::auth::AuthProvider::Microsoft, + } + } +} + +impl From for Option { + fn from(d: ExistingTunnelArgs) -> Option { + if let (Some(tunnel_id), Some(tunnel_name), Some(cluster), Some(host_token)) = + (d.tunnel_id, d.tunnel_name, d.cluster, d.host_token) + { + Some(dev_tunnels::ExistingTunnel { + tunnel_id, + tunnel_name, + host_token, + cluster, + }) + } else { + None + } + } +} + +struct TunnelServiceContainer { + args: CliCore, +} + +impl TunnelServiceContainer { + fn new(args: CliCore) -> Self { + Self { args } + } +} + +#[async_trait] +impl ServiceContainer for TunnelServiceContainer { + async fn run_service( + &mut self, + log: log::Logger, + launcher_paths: LauncherPaths, + shutdown_rx: mpsc::Receiver, + ) -> Result<(), AnyError> { + let csa = (&self.args).into(); + serve_with_csa( + launcher_paths, + log, + TunnelServeArgs { + random_name: true, // avoid prompting + ..Default::default() + }, + csa, + Some(shutdown_rx), + ) + .await?; + Ok(()) + } +} +/// Describes the signal to manully stop the server +pub enum ShutdownSignal { + CtrlC, + ParentProcessKilled, + ServiceStopped, +} + +impl fmt::Display for ShutdownSignal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ShutdownSignal::CtrlC => write!(f, "Ctrl-C received"), + ShutdownSignal::ParentProcessKilled => write!(f, "Parent process no longer exists"), + ShutdownSignal::ServiceStopped => write!(f, "Service stopped"), + } + } +} + +pub async fn service( + ctx: CommandContext, + service_args: TunnelServiceSubCommands, +) -> Result { + let manager = create_service_manager(ctx.log.clone()); + match service_args { + TunnelServiceSubCommands::Install => { + // ensure logged in, otherwise subsequent serving will fail + Auth::new(&ctx.paths, ctx.log.clone()) + .get_credential() + .await?; + + // likewise for license consent + legal::require_consent(&ctx.paths, false)?; + + let current_exe = + std::env::current_exe().map_err(|e| wrap(e, "could not get current exe"))?; + + manager.register( + current_exe, + &[ + "--cli-data-dir", + ctx.paths.root().as_os_str().to_string_lossy().as_ref(), + "tunnel", + "service", + "internal-run", + ], + )?; + ctx.log.result("Service successfully installed! You can use `code tunnel service log` to monitor it, and `code tunnel service uninstall` to remove it."); + } + TunnelServiceSubCommands::Uninstall => { + manager.unregister()?; + } + TunnelServiceSubCommands::InternalRun => { + manager.run(ctx.paths.clone(), TunnelServiceContainer::new(ctx.args))?; + } + } + + Ok(0) +} + +pub async fn user(ctx: CommandContext, user_args: TunnelUserSubCommands) -> Result { + let auth = Auth::new(&ctx.paths, ctx.log.clone()); + match user_args { + TunnelUserSubCommands::Login(login_args) => { + auth.login( + login_args.provider.map(|p| p.into()), + login_args.access_token.to_owned(), + ) + .await?; + } + TunnelUserSubCommands::Logout => { + auth.clear_credentials()?; + } + TunnelUserSubCommands::Show => { + if let Ok(Some(_)) = auth.get_current_credential() { + ctx.log.result("logged in"); + } else { + ctx.log.result("not logged in"); + return Ok(1); + } + } + } + + Ok(0) +} + +/// Remove the tunnel used by this gateway, if any. +pub async fn rename(ctx: CommandContext, rename_args: TunnelRenameArgs) -> Result { + let auth = Auth::new(&ctx.paths, ctx.log.clone()); + let mut dt = dev_tunnels::DevTunnels::new(&ctx.log, auth, &ctx.paths); + dt.rename_tunnel(&rename_args.name).await?; + ctx.log.result(&format!( + "Successfully renamed this gateway to {}", + &rename_args.name + )); + + Ok(0) +} + +/// Remove the tunnel used by this gateway, if any. +pub async fn unregister(ctx: CommandContext) -> Result { + let auth = Auth::new(&ctx.paths, ctx.log.clone()); + let mut dt = dev_tunnels::DevTunnels::new(&ctx.log, auth, &ctx.paths); + dt.remove_tunnel().await?; + Ok(0) +} + +/// Removes unused servers. +pub async fn prune(ctx: CommandContext) -> Result { + get_all_servers(&ctx.paths) + .into_iter() + .map(|s| s.server_paths(&ctx.paths)) + .filter(|s| s.get_running_pid().is_none()) + .try_for_each(|s| { + ctx.log + .result(&format!("Deleted {}", s.server_dir.display())); + s.delete() + }) + .map_err(AnyError::from)?; + + ctx.log.result("Successfully removed all unused servers"); + + Ok(0) +} + +/// Starts the gateway server. +pub async fn serve(ctx: CommandContext, gateway_args: TunnelServeArgs) -> Result { + let CommandContext { + log, paths, args, .. + } = ctx; + + legal::require_consent(&paths, gateway_args.accept_server_license_terms)?; + + let csa = (&args).into(); + serve_with_csa(paths, log, gateway_args, csa, None).await +} + +async fn serve_with_csa( + paths: LauncherPaths, + log: Logger, + gateway_args: TunnelServeArgs, + csa: CodeServerArgs, + shutdown_rx: Option>, +) -> Result { + // Intentionally read before starting the server. If the server updated and + // respawn is requested, the old binary will get renamed, and then + // current_exe will point to the wrong path. + let current_exe = std::env::current_exe().unwrap(); + let platform = spanf!(log, log.span("prereq"), PreReqChecker::new().verify())?; + + let auth = Auth::new(&paths, log.clone()); + let mut dt = dev_tunnels::DevTunnels::new(&log, auth, &paths); + let tunnel = if let Some(d) = gateway_args.tunnel.clone().into() { + dt.start_existing_tunnel(d).await + } else { + dt.start_new_launcher_tunnel(gateway_args.name, gateway_args.random_name) + .await + }?; + + let shutdown_tx = if let Some(tx) = shutdown_rx { + tx + } else { + let (tx, rx) = mpsc::channel::(2); + if let Some(process_id) = gateway_args.parent_process_id { + match Pid::from_str(&process_id) { + Ok(pid) => { + let tx = tx.clone(); + info!(log, "checking for parent process {}", process_id); + tokio::spawn(async move { + let mut s = sysinfo::System::new(); + while s.refresh_process(pid) { + sleep(Duration::from_millis(2000)).await; + } + tx.send(ShutdownSignal::ParentProcessKilled).await.ok(); + }); + } + Err(_) => { + info!(log, "invalid parent process id: {}", process_id); + } + } + } + tokio::spawn(async move { + tokio::signal::ctrl_c().await.ok(); + tx.send(ShutdownSignal::CtrlC).await.ok(); + }); + rx + }; + + let mut r = crate::tunnels::serve(&log, tunnel, &paths, &csa, platform, shutdown_tx).await?; + r.tunnel.close().await.ok(); + + if r.respawn { + warning!(log, "respawn requested, starting new server"); + // reuse current args, but specify no-forward since tunnels will + // already be running in this process, and we cannot do a login + let args = std::env::args().skip(1).collect::>(); + let exit = std::process::Command::new(current_exe) + .args(args) + .spawn() + .map_err(|e| wrap(e, "error respawning after update"))? + .wait() + .map_err(|e| wrap(e, "error waiting for child"))?; + + return Ok(exit.code().unwrap_or(1)); + } + + Ok(0) +} diff --git a/cli/src/commands/update.rs b/cli/src/commands/update.rs new file mode 100644 index 00000000000..7e1db89964c --- /dev/null +++ b/cli/src/commands/update.rs @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use indicatif::ProgressBar; + +use crate::{ + self_update::SelfUpdate, + update_service::UpdateService, + util::{errors::AnyError, input::ProgressBarReporter}, +}; + +use super::{args::StandaloneUpdateArgs, CommandContext}; + +pub async fn update(ctx: CommandContext, args: StandaloneUpdateArgs) -> Result { + let update_service = UpdateService::new(ctx.log.clone(), ctx.http.clone()); + let update_service = SelfUpdate::new(&update_service)?; + + let current_version = update_service.get_current_release().await?; + if update_service.is_up_to_date_with(¤t_version) { + ctx.log.result(format!( + "VS Code is already to to date ({})", + current_version.commit + )); + return Ok(1); + } + + if args.check { + ctx.log + .result(format!("Update to {} is available", current_version)); + return Ok(0); + } + + let pb = ProgressBar::new(1); + pb.set_message("Downloading..."); + update_service + .do_update(¤t_version, ProgressBarReporter::from(pb)) + .await?; + ctx.log + .result(format!("Successfully updated to {}", current_version)); + + Ok(0) +} diff --git a/cli/src/commands/version.rs b/cli/src/commands/version.rs new file mode 100644 index 00000000000..816c53ddf9f --- /dev/null +++ b/cli/src/commands/version.rs @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::path::{Path, PathBuf}; + +use crate::{ + desktop::{prompt_to_install, CodeVersionManager, RequestedVersion}, + log, + util::{ + errors::{AnyError, NoInstallInUserProvidedPath}, + prereqs::PreReqChecker, + }, +}; + +use super::{args::UseVersionArgs, CommandContext}; + +pub async fn switch_to(ctx: CommandContext, args: UseVersionArgs) -> Result { + let platform = PreReqChecker::new().verify().await?; + let vm = CodeVersionManager::new(ctx.log.clone(), &ctx.paths, platform); + let version = RequestedVersion::try_from(args.name.as_str())?; + + let maybe_path = match args.install_dir { + Some(d) => Some( + CodeVersionManager::get_entrypoint_for_install_dir(&PathBuf::from(&d)) + .await + .ok_or(NoInstallInUserProvidedPath(d))?, + ), + None => vm.try_get_entrypoint(&version).await, + }; + + match maybe_path { + Some(p) => { + vm.set_preferred_version(version.clone(), p.clone()).await?; + print_now_using(&ctx.log, &version, &p); + Ok(0) + } + None => { + prompt_to_install(&version); + Ok(1) + } + } +} + +pub async fn show(ctx: CommandContext) -> Result { + let platform = PreReqChecker::new().verify().await?; + let vm = CodeVersionManager::new(ctx.log.clone(), &ctx.paths, platform); + + let version = vm.get_preferred_version(); + println!("Current quality: {}", version); + match vm.try_get_entrypoint(&version).await { + Some(p) => println!("Installation path: {}", p.display()), + None => println!("No existing installation found"), + } + + Ok(0) +} + +fn print_now_using(log: &log::Logger, version: &RequestedVersion, path: &Path) { + log.result(&format!( + "Now using VS Code {} from {}", + version, + path.display() + )); +} diff --git a/cli/src/constants.rs b/cli/src/constants.rs new file mode 100644 index 00000000000..1541a6a43a4 --- /dev/null +++ b/cli/src/constants.rs @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::collections::HashMap; + +use lazy_static::lazy_static; + +use crate::options::Quality; + +pub const CONTROL_PORT: u16 = 31545; +pub const PROTOCOL_VERSION: u32 = 1; + +pub const VSCODE_CLI_VERSION: Option<&'static str> = option_env!("VSCODE_CLI_VERSION"); +pub const VSCODE_CLI_AI_KEY: Option<&'static str> = option_env!("VSCODE_CLI_AI_KEY"); +pub const VSCODE_CLI_AI_ENDPOINT: Option<&'static str> = option_env!("VSCODE_CLI_AI_ENDPOINT"); +pub const VSCODE_CLI_QUALITY: Option<&'static str> = option_env!("VSCODE_CLI_QUALITY"); +pub const VSCODE_CLI_COMMIT: Option<&'static str> = option_env!("VSCODE_CLI_COMMIT"); +pub const VSCODE_CLI_UPDATE_ENDPOINT: Option<&'static str> = + option_env!("VSCODE_CLI_UPDATE_ENDPOINT"); + +pub const TUNNEL_SERVICE_USER_AGENT_ENV_VAR: &str = "TUNNEL_SERVICE_USER_AGENT"; + +// JSON map of quality names to arrays of app IDs used for them, for example, `{"stable":["ABC123"]}` +const VSCODE_CLI_WIN32_APP_IDS: Option<&'static str> = option_env!("VSCODE_CLI_WIN32_APP_IDS"); +// JSON map of quality names to download URIs +const VSCODE_CLI_QUALITY_DOWNLOAD_URIS: Option<&'static str> = + option_env!("VSCODE_CLI_QUALITY_DOWNLOAD_URIS"); + +pub fn get_default_user_agent() -> String { + format!( + "vscode-server-launcher/{}", + VSCODE_CLI_VERSION.unwrap_or("dev") + ) +} + +lazy_static! { + pub static ref TUNNEL_SERVICE_USER_AGENT: String = + match std::env::var(TUNNEL_SERVICE_USER_AGENT_ENV_VAR) { + Ok(ua) if !ua.is_empty() => format!("{} {}", ua, get_default_user_agent()), + _ => get_default_user_agent(), + }; + pub static ref WIN32_APP_IDS: Option>> = + VSCODE_CLI_WIN32_APP_IDS.and_then(|s| serde_json::from_str(s).unwrap()); + pub static ref QUALITY_DOWNLOAD_URIS: Option> = + VSCODE_CLI_QUALITY_DOWNLOAD_URIS.and_then(|s| serde_json::from_str(s).unwrap()); +} diff --git a/extensions/vscode-notebook-tests/test/second.vsctestnb b/cli/src/desktop.rs similarity index 76% rename from extensions/vscode-notebook-tests/test/second.vsctestnb rename to cli/src/desktop.rs index a4a092d8349..9f4409d0f0d 100644 --- a/extensions/vscode-notebook-tests/test/second.vsctestnb +++ b/cli/src/desktop.rs @@ -2,3 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ + +mod version_manager; + +pub use version_manager::{prompt_to_install, CodeVersionManager, RequestedVersion}; diff --git a/cli/src/desktop/version_manager.rs b/cli/src/desktop/version_manager.rs new file mode 100644 index 00000000000..3fd1b7c35f3 --- /dev/null +++ b/cli/src/desktop/version_manager.rs @@ -0,0 +1,579 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::{ + ffi::OsString, + fmt, io, + path::{Path, PathBuf}, +}; + +use lazy_static::lazy_static; +use regex::Regex; +use serde::{Deserialize, Serialize}; + +use crate::{ + constants::QUALITY_DOWNLOAD_URIS, + log, + options::{self, Quality}, + state::{LauncherPaths, PersistedState}, + update_service::Platform, + util::errors::{AnyError, InvalidRequestedVersion}, +}; + +/// Parsed instance that a user can request. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(tag = "t", content = "c")] +pub enum RequestedVersion { + Quality(options::Quality), + Version { + version: String, + quality: options::Quality, + }, + Commit { + commit: String, + quality: options::Quality, + }, + Path(String), +} + +lazy_static! { + static ref SEMVER_RE: Regex = Regex::new(r"^\d+\.\d+\.\d+(-insider)?$").unwrap(); + static ref COMMIT_RE: Regex = Regex::new(r"^[a-z]+/[a-e0-f]{40}$").unwrap(); +} + +impl RequestedVersion { + pub fn get_command(&self) -> String { + match self { + RequestedVersion::Quality(quality) => { + format!("code version use {}", quality.get_machine_name()) + } + RequestedVersion::Version { version, .. } => { + format!("code version use {}", version) + } + RequestedVersion::Commit { commit, quality } => { + format!("code version use {}/{}", quality.get_machine_name(), commit) + } + RequestedVersion::Path(path) => { + format!("code version use {}", path) + } + } + } +} + +impl std::fmt::Display for RequestedVersion { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RequestedVersion::Quality(quality) => write!(f, "{}", quality.get_capitalized_name()), + RequestedVersion::Version { version, .. } => { + write!(f, "{}", version) + } + RequestedVersion::Commit { commit, quality } => { + write!(f, "{}/{}", quality, commit) + } + RequestedVersion::Path(path) => write!(f, "{}", path), + } + } +} + +impl TryFrom<&str> for RequestedVersion { + type Error = InvalidRequestedVersion; + + fn try_from(s: &str) -> Result { + if let Ok(quality) = options::Quality::try_from(s) { + return Ok(RequestedVersion::Quality(quality)); + } + + if SEMVER_RE.is_match(s) { + return Ok(RequestedVersion::Version { + quality: if s.ends_with("-insider") { + options::Quality::Insiders + } else { + options::Quality::Stable + }, + version: s.to_string(), + }); + } + + if Path::is_absolute(&PathBuf::from(s)) { + return Ok(RequestedVersion::Path(s.to_string())); + } + + if COMMIT_RE.is_match(s) { + let idx = s.find('/').expect("expected a /"); + if let Ok(quality) = options::Quality::try_from(&s[0..idx]) { + return Ok(RequestedVersion::Commit { + commit: s[idx + 1..].to_string(), + quality, + }); + } + } + + Err(InvalidRequestedVersion()) + } +} + +#[derive(Serialize, Deserialize, Clone, Default)] +struct Stored { + /// Map of requested versions to locations where those versions are installed. + versions: Vec<(RequestedVersion, OsString)>, + current: usize, +} + +pub struct CodeVersionManager { + state: PersistedState, + log: log::Logger, +} + +impl CodeVersionManager { + pub fn new(log: log::Logger, lp: &LauncherPaths, _platform: Platform) -> Self { + CodeVersionManager { + log, + state: PersistedState::new(lp.root().join("versions.json")), + } + } + + /// Tries to find the binary entrypoint for VS Code installed in the path. + pub async fn get_entrypoint_for_install_dir(path: &Path) -> Option { + use tokio::sync::mpsc; + + let (tx, mut rx) = mpsc::channel(1); + + // Look for all the possible paths in parallel + for entry in DESKTOP_CLI_RELATIVE_PATH.split(',') { + let my_path = path.join(entry); + let my_tx = tx.clone(); + tokio::spawn(async move { + if tokio::fs::metadata(&my_path).await.is_ok() { + my_tx.send(my_path).await.ok(); + } + }); + } + + drop(tx); // drop so rx gets None if no sender emits + + rx.recv().await + } + + /// Sets the "version" as the persisted one for the user. + pub async fn set_preferred_version( + &self, + version: RequestedVersion, + path: PathBuf, + ) -> Result<(), AnyError> { + let mut stored = self.state.load(); + stored.current = self.store_version_path(&mut stored, version, path); + self.state.save(stored)?; + Ok(()) + } + + /// Stores or updates the path used for the given version. Returns the index + /// that the path exists at. + fn store_version_path( + &self, + state: &mut Stored, + version: RequestedVersion, + path: PathBuf, + ) -> usize { + if let Some(i) = state.versions.iter().position(|(v, _)| v == &version) { + state.versions[i].1 = path.into_os_string(); + i + } else { + state + .versions + .push((version.clone(), path.into_os_string())); + state.versions.len() - 1 + } + } + + /// Gets the currently preferred version based on set_preferred_version. + pub fn get_preferred_version(&self) -> RequestedVersion { + let stored = self.state.load(); + stored + .versions + .get(stored.current) + .map(|(v, _)| v.clone()) + .unwrap_or(RequestedVersion::Quality(options::Quality::Stable)) + } + + /// Tries to get the entrypoint for the version, if one can be found. + pub async fn try_get_entrypoint(&self, version: &RequestedVersion) -> Option { + let mut state = self.state.load(); + if let Some((_, install_path)) = state.versions.iter().find(|(v, _)| v == version) { + let p = PathBuf::from(install_path); + if p.exists() { + return Some(p); + } + } + + // For simple quality requests, see if that's installed already on the system + let candidates = match &version { + RequestedVersion::Quality(q) => match detect_installed_program(&self.log, *q) { + Ok(p) => p, + Err(e) => { + warning!(self.log, "error looking up installed applications: {}", e); + return None; + } + }, + _ => return None, + }; + + let found = match candidates.into_iter().next() { + Some(p) => p, + None => return None, + }; + + // stash the found path for faster lookup + self.store_version_path(&mut state, version.clone(), found.clone()); + if let Err(e) = self.state.save(state) { + debug!(self.log, "error caching version path: {}", e); + } + + Some(found) + } +} + +/// Shows a nice UI prompt to users asking them if they want to install the +/// requested version. +pub fn prompt_to_install(version: &RequestedVersion) { + println!("No installation of VS Code {} was found.", version); + + if let RequestedVersion::Quality(quality) = version { + if let Some(uri) = QUALITY_DOWNLOAD_URIS.as_ref().and_then(|m| m.get(quality)) { + // todo: on some platforms, we may be able to help automate installation. For example, + // we can unzip the app ourselves on macOS and on windows we can download and spawn the GUI installer + #[cfg(target_os = "linux")] + println!("Install it from your system's package manager or {}, restart your shell, and try again.", uri); + #[cfg(target_os = "macos")] + println!("Download and unzip it from {} and try again.", uri); + #[cfg(target_os = "windows")] + println!("Install it from {} and try again.", uri); + } + } + + println!(); + println!("If you already installed VS Code and we didn't detect it, run `{} --install-dir /path/to/installation`", version.get_command()); +} + +#[cfg(target_os = "macos")] +fn detect_installed_program(log: &log::Logger, quality: Quality) -> io::Result> { + // easy, fast detection for where apps are usually installed + let mut probable = PathBuf::from("/Applications"); + let app_name = quality.get_macos_app_name(); + probable.push(format!("{}.app", app_name)); + if probable.exists() { + probable.extend(["Contents/Resources", "app", "bin", "code"]); + return Ok(vec![probable]); + } + + // _Much_ slower detection using the system_profiler (~10s for me). While the + // profiler can output nicely structure plist xml, pulling in an xml parser + // just for this is overkill. The default output looks something like... + // + // Visual Studio Code - Exploration 2: + // + // Version: 1.73.0-exploration + // Obtained from: Identified Developer + // Last Modified: 9/23/22, 10:16 AM + // Kind: Intel + // Signed by: Developer ID Application: Microsoft Corporation (UBF8T346G9), Developer ID Certification Authority, Apple Root CA + // Location: /Users/connor/Downloads/Visual Studio Code - Exploration 2.app + // + // So, use a simple state machine that looks for the first line, and then for + // the `Location:` line for the path. + info!(log, "Searching for installations on your machine, this is done once and will take about 10 seconds..."); + + let stdout = std::process::Command::new("system_profiler") + .args(["SPApplicationsDataType", "-detailLevel", "mini"]) + .output()? + .stdout; + + enum State { + LookingForName, + LookingForLocation, + } + + let mut state = State::LookingForName; + let mut output: Vec = vec![]; + const LOCATION_PREFIX: &str = "Location:"; + for mut line in String::from_utf8_lossy(&stdout).lines() { + line = line.trim(); + match state { + State::LookingForName => { + if line.starts_with(app_name) && line.ends_with(':') { + state = State::LookingForLocation; + } + } + State::LookingForLocation => { + if line.starts_with(LOCATION_PREFIX) { + output.push( + [ + &line[LOCATION_PREFIX.len()..].trim(), + "Contents/Resources", + "app", + "bin", + "code", + ] + .iter() + .collect(), + ); + state = State::LookingForName; + } + } + } + } + + // Sort shorter paths to the front, preferring "more global" installs, and + // incidentally preferring local installs over Parallels 'installs'. + output.sort_by(|a, b| a.as_os_str().len().cmp(&b.as_os_str().len())); + + Ok(output) +} + +#[cfg(windows)] +fn detect_installed_program(_log: &log::Logger, quality: Quality) -> io::Result> { + use crate::constants::WIN32_APP_IDS; + use winreg::enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; + use winreg::RegKey; + + let mut output: Vec = vec![]; + let app_ids = match WIN32_APP_IDS.as_ref().and_then(|m| m.get(&quality)) { + Some(ids) => ids, + None => return Ok(output), + }; + + let scopes = [ + ( + HKEY_LOCAL_MACHINE, + "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + ), + ( + HKEY_LOCAL_MACHINE, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + ), + ( + HKEY_CURRENT_USER, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + ), + ]; + + for (scope, key) in scopes { + let cur_ver = match RegKey::predef(scope).open_subkey(key) { + Ok(k) => k, + Err(_) => continue, + }; + + for key in cur_ver.enum_keys().flatten() { + if app_ids.iter().any(|id| key.contains(id)) { + let sk = cur_ver.open_subkey(&key)?; + if let Ok(location) = sk.get_value::("InstallLocation") { + output.push( + [ + location.as_str(), + "bin", + match quality { + Quality::Exploration => "code-exploration.cmd", + Quality::Insiders => "code-insiders.cmd", + Quality::Stable => "code.cmd", + }, + ] + .iter() + .collect(), + ) + } + } + } + } + + Ok(output) +} + +// Looks for the given binary name in the PATH, returning all candidate matches. +// Based on https://github.dev/microsoft/vscode-js-debug/blob/7594d05518df6700df51771895fcad0ddc7f92f9/src/common/pathUtils.ts#L15 +#[cfg(target_os = "linux")] +fn detect_installed_program(log: &log::Logger, quality: Quality) -> io::Result> { + let path = match std::env::var("PATH") { + Ok(p) => p, + Err(e) => { + info!(log, "PATH is empty ({}), skipping detection", e); + return Ok(vec![]); + } + }; + + let name = quality.get_commandline_name(); + let current_exe = std::env::current_exe().expect("expected to read current exe"); + let mut output = vec![]; + for dir in path.split(':') { + let target: PathBuf = [dir, name].iter().collect(); + match std::fs::canonicalize(&target) { + Ok(m) if m == current_exe => continue, + Ok(_) => {} + Err(_) => continue, + }; + + // note: intentionally store the non-canonicalized version, since if it's a + // symlink, (1) it's probably desired to use it and (2) resolving the link + // breaks snap installations. + output.push(target); + } + + Ok(output) +} + +const DESKTOP_CLI_RELATIVE_PATH: &str = if cfg!(target_os = "macos") { + "Contents/Resources/app/bin/code" +} else if cfg!(target_os = "windows") { + "bin/code.cmd,bin/code-insiders.cmd,bin/code-exploration.cmd" +} else { + "bin/code,bin/code-insiders,bin/code-exploration" +}; + +#[cfg(test)] +mod tests { + use std::{ + fs::{create_dir_all, File}, + io::Write, + }; + + use super::*; + + fn make_fake_vscode_install(path: &Path) { + let bin = DESKTOP_CLI_RELATIVE_PATH + .split(',') + .next() + .expect("expected exe path"); + + let binary_file_path = path.join(bin); + let parent_dir_path = binary_file_path.parent().expect("expected parent path"); + + create_dir_all(parent_dir_path).expect("expected to create parent dir"); + + let mut binary_file = File::create(binary_file_path).expect("expected to make file"); + binary_file + .write_all(b"") + .expect("expected to write binary"); + } + + fn make_multiple_vscode_install() -> tempfile::TempDir { + let dir = tempfile::tempdir().expect("expected to make temp dir"); + make_fake_vscode_install(&dir.path().join("desktop/stable")); + make_fake_vscode_install(&dir.path().join("desktop/1.68.2")); + dir + } + + #[test] + fn test_detect_installed_program() { + // developers can run this test and debug output manually; VS Code will not + // be installed in CI, so the test only makes sure it doesn't error out + let result = detect_installed_program(&log::Logger::test(), Quality::Insiders); + println!("result: {:?}", result); + assert!(result.is_ok()); + } + + #[test] + fn test_requested_version_parses() { + assert_eq!( + RequestedVersion::try_from("1.2.3").unwrap(), + RequestedVersion::Version { + quality: options::Quality::Stable, + version: "1.2.3".to_string(), + } + ); + + assert_eq!( + RequestedVersion::try_from("1.2.3-insider").unwrap(), + RequestedVersion::Version { + quality: options::Quality::Insiders, + version: "1.2.3-insider".to_string(), + } + ); + + assert_eq!( + RequestedVersion::try_from("stable").unwrap(), + RequestedVersion::Quality(options::Quality::Stable) + ); + + assert_eq!( + RequestedVersion::try_from("insiders").unwrap(), + RequestedVersion::Quality(options::Quality::Insiders) + ); + + assert_eq!( + RequestedVersion::try_from("insiders/92fd228156aafeb326b23f6604028d342152313b") + .unwrap(), + RequestedVersion::Commit { + commit: "92fd228156aafeb326b23f6604028d342152313b".to_string(), + quality: options::Quality::Insiders + } + ); + + assert_eq!( + RequestedVersion::try_from("stable/92fd228156aafeb326b23f6604028d342152313b").unwrap(), + RequestedVersion::Commit { + commit: "92fd228156aafeb326b23f6604028d342152313b".to_string(), + quality: options::Quality::Stable + } + ); + + let exe = std::env::current_exe() + .expect("expected to get exe") + .to_string_lossy() + .to_string(); + assert_eq!( + RequestedVersion::try_from(exe.as_str()).unwrap(), + RequestedVersion::Path(exe), + ); + } + + #[tokio::test] + async fn test_set_preferred_version() { + let dir = make_multiple_vscode_install(); + let lp = LauncherPaths::new_without_replacements(dir.path().to_owned()); + let vm1 = CodeVersionManager::new(log::Logger::test(), &lp, Platform::LinuxARM64); + + assert_eq!( + vm1.get_preferred_version(), + RequestedVersion::Quality(options::Quality::Stable) + ); + vm1.set_preferred_version( + RequestedVersion::Quality(options::Quality::Exploration), + dir.path().join("desktop/stable"), + ) + .await + .expect("expected to store"); + vm1.set_preferred_version( + RequestedVersion::Quality(options::Quality::Insiders), + dir.path().join("desktop/stable"), + ) + .await + .expect("expected to store"); + assert_eq!( + vm1.get_preferred_version(), + RequestedVersion::Quality(options::Quality::Insiders) + ); + + let vm2 = CodeVersionManager::new(log::Logger::test(), &lp, Platform::LinuxARM64); + assert_eq!( + vm2.get_preferred_version(), + RequestedVersion::Quality(options::Quality::Insiders) + ); + } + + #[tokio::test] + async fn test_gets_entrypoint() { + let dir = make_multiple_vscode_install(); + + assert!(CodeVersionManager::get_entrypoint_for_install_dir( + &dir.path().join("desktop").join("stable") + ) + .await + .is_some()); + + assert!( + CodeVersionManager::get_entrypoint_for_install_dir(&dir.path().join("invalid")) + .await + .is_none() + ); + } +} diff --git a/cli/src/lib.rs b/cli/src/lib.rs new file mode 100644 index 00000000000..a1ebce4b0ef --- /dev/null +++ b/cli/src/lib.rs @@ -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. + *--------------------------------------------------------------------------------------------*/ + +// todo: we should reduce the exported surface area over time as things are +// moved into a common CLI +pub mod auth; +pub mod constants; +#[macro_use] +pub mod log; +pub mod commands; +pub mod desktop; +pub mod options; +pub mod state; +pub mod tunnels; +pub mod self_update; +pub mod update_service; +pub mod util; diff --git a/cli/src/log.rs b/cli/src/log.rs new file mode 100644 index 00000000000..d31e02fb3bf --- /dev/null +++ b/cli/src/log.rs @@ -0,0 +1,397 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use chrono::Local; +use opentelemetry::{ + sdk::trace::{Tracer, TracerProvider}, + trace::{SpanBuilder, Tracer as TraitTracer, TracerProvider as TracerProviderTrait}, +}; +use std::fmt; +use std::{env, path::Path, sync::Arc}; +use std::{ + io::Write, + sync::atomic::{AtomicU32, Ordering}, +}; + +const NO_COLOR_ENV: &str = "NO_COLOR"; + +static INSTANCE_COUNTER: AtomicU32 = AtomicU32::new(0); + +// Gets a next incrementing number that can be used in logs +pub fn next_counter() -> u32 { + INSTANCE_COUNTER.fetch_add(1, Ordering::SeqCst) +} + +// Log level +#[derive(clap::ArgEnum, PartialEq, Eq, PartialOrd, Clone, Copy, Debug)] +pub enum Level { + Trace = 0, + Debug, + Info, + Warn, + Error, + Critical, + Off, +} + +impl Default for Level { + fn default() -> Self { + Level::Info + } +} + +impl fmt::Display for Level { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Level::Critical => write!(f, "critical"), + Level::Debug => write!(f, "debug"), + Level::Error => write!(f, "error"), + Level::Info => write!(f, "info"), + Level::Off => write!(f, "off"), + Level::Trace => write!(f, "trace"), + Level::Warn => write!(f, "warn"), + } + } +} + +impl Level { + pub fn name(&self) -> Option<&str> { + match self { + Level::Trace => Some("trace"), + Level::Debug => Some("debug"), + Level::Info => Some("info"), + Level::Warn => Some("warn"), + Level::Error => Some("error"), + Level::Critical => Some("critical"), + Level::Off => None, + } + } + + pub fn color_code(&self) -> Option<&str> { + if env::var(NO_COLOR_ENV).is_ok() || !atty::is(atty::Stream::Stdout) { + return None; + } + + match self { + Level::Trace => None, + Level::Debug => Some("\x1b[36m"), + Level::Info => Some("\x1b[35m"), + Level::Warn => Some("\x1b[33m"), + Level::Error => Some("\x1b[31m"), + Level::Critical => Some("\x1b[31m"), + Level::Off => None, + } + } + + pub fn to_u8(self) -> u8 { + self as u8 + } +} + +pub fn new_tunnel_prefix() -> String { + format!("[tunnel.{}]", next_counter()) +} + +pub fn new_code_server_prefix() -> String { + format!("[codeserver.{}]", next_counter()) +} + +pub fn new_rpc_prefix() -> String { + format!("[rpc.{}]", next_counter()) +} + +// Base logger implementation +#[derive(Clone)] +pub struct Logger { + tracer: Tracer, + sink: Vec>, + prefix: Option, +} + +// Copy trick from https://stackoverflow.com/a/30353928 +pub trait LogSinkClone { + fn clone_box(&self) -> Box; +} + +impl LogSinkClone for T +where + T: 'static + LogSink + Clone, +{ + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } +} + +pub trait LogSink: LogSinkClone + Sync + Send { + fn write_log(&self, level: Level, prefix: &str, message: &str); + fn write_result(&self, message: &str); +} + +impl Clone for Box { + fn clone(&self) -> Box { + self.clone_box() + } +} + +#[derive(Clone)] +pub struct StdioLogSink { + level: Level, +} + +impl LogSink for StdioLogSink { + fn write_log(&self, level: Level, prefix: &str, message: &str) { + if level < self.level { + return; + } + + emit(level, prefix, message); + } + + fn write_result(&self, message: &str) { + println!("{}", message); + } +} + +#[derive(Clone)] +pub struct FileLogSink { + level: Level, + file: Arc>, +} + +impl FileLogSink { + pub fn new(level: Level, path: &Path) -> std::io::Result { + let file = std::fs::File::create(path)?; + Ok(Self { + level, + file: Arc::new(std::sync::Mutex::new(file)), + }) + } +} + +impl LogSink for FileLogSink { + fn write_log(&self, level: Level, prefix: &str, message: &str) { + if level < self.level { + return; + } + + let line = format(level, prefix, message); + + // ignore any errors, not much we can do if logging fails... + self.file.lock().unwrap().write_all(line.as_bytes()).ok(); + } + + fn write_result(&self, _message: &str) {} +} + +impl Logger { + pub fn test() -> Self { + Self { + tracer: TracerProvider::builder().build().tracer("codeclitest"), + sink: vec![], + prefix: None, + } + } + + pub fn new(tracer: Tracer, level: Level) -> Self { + Self { + tracer, + sink: vec![Box::new(StdioLogSink { level })], + prefix: None, + } + } + + pub fn span(&self, name: &str) -> SpanBuilder { + self.tracer.span_builder(format!("serverlauncher/{}", name)) + } + + pub fn tracer(&self) -> &Tracer { + &self.tracer + } + + pub fn emit(&self, level: Level, message: &str) { + let prefix = self.prefix.as_deref().unwrap_or(""); + for sink in &self.sink { + sink.write_log(level, prefix, message); + } + } + + pub fn result(&self, message: impl AsRef) { + for sink in &self.sink { + sink.write_result(message.as_ref()); + } + } + + pub fn prefixed(&self, prefix: &str) -> Logger { + Logger { + prefix: Some(match &self.prefix { + Some(p) => format!("{}{} ", p, prefix), + None => format!("{} ", prefix), + }), + ..self.clone() + } + } + + /// Creates a new logger with the additional log sink added. + pub fn tee(&self, sink: T) -> Logger + where + T: LogSink + 'static, + { + let mut new_sinks = self.sink.clone(); + new_sinks.push(Box::new(sink)); + + Logger { + sink: new_sinks, + ..self.clone() + } + } + + pub fn get_download_logger<'a>(&'a self, prefix: &'static str) -> DownloadLogger<'a> { + DownloadLogger { + prefix, + logger: self, + } + } +} + +pub struct DownloadLogger<'a> { + prefix: &'static str, + logger: &'a Logger, +} + +impl<'a> crate::util::io::ReportCopyProgress for DownloadLogger<'a> { + fn report_progress(&mut self, bytes_so_far: u64, total_bytes: u64) { + if total_bytes > 0 { + self.logger.emit( + Level::Trace, + &format!( + "{} {}/{} ({:.0}%)", + self.prefix, + bytes_so_far, + total_bytes, + (bytes_so_far as f64 / total_bytes as f64) * 100.0, + ), + ); + } else { + self.logger.emit( + Level::Trace, + &format!("{} {}/{}", self.prefix, bytes_so_far, total_bytes,), + ); + } + } +} + +pub fn format(level: Level, prefix: &str, message: &str) -> String { + let current = Local::now(); + let timestamp = current.format("%Y-%m-%d %H:%M:%S").to_string(); + + let name = level.name().unwrap(); + + if let Some(c) = level.color_code() { + format!( + "\x1b[2m[{}]\x1b[0m {}{}\x1b[0m {}{}\n", + timestamp, c, name, prefix, message + ) + } else { + format!("[{}] {} {}{}\n", timestamp, name, prefix, message) + } +} + +pub fn emit(level: Level, prefix: &str, message: &str) { + let line = format(level, prefix, message); + if level == Level::Trace { + print!("\x1b[2m{}\x1b[0m", line); + } else { + print!("{}", line); + } +} + +#[macro_export] +macro_rules! error { + ($logger:expr, $str:expr) => { + $logger.emit(log::Level::Error, $str) + }; + ($logger:expr, $($fmt:expr),+) => { + $logger.emit(log::Level::Error, &format!($($fmt),+)) + }; + } + +#[macro_export] +macro_rules! trace { + ($logger:expr, $str:expr) => { + $logger.emit(log::Level::Trace, $str) + }; + ($logger:expr, $($fmt:expr),+) => { + $logger.emit(log::Level::Trace, &format!($($fmt),+)) + }; + } + +#[macro_export] +macro_rules! debug { + ($logger:expr, $str:expr) => { + $logger.emit(log::Level::Debug, $str) + }; + ($logger:expr, $($fmt:expr),+) => { + $logger.emit(log::Level::Debug, &format!($($fmt),+)) + }; + } + +#[macro_export] +macro_rules! info { + ($logger:expr, $str:expr) => { + $logger.emit(log::Level::Info, $str) + }; + ($logger:expr, $($fmt:expr),+) => { + $logger.emit(log::Level::Info, &format!($($fmt),+)) + }; + } + +#[macro_export] +macro_rules! warning { + ($logger:expr, $str:expr) => { + $logger.emit(log::Level::Warn, $str) + }; + ($logger:expr, $($fmt:expr),+) => { + $logger.emit(log::Level::Warn, &format!($($fmt),+)) + }; + } + +#[macro_export] +macro_rules! span { + ($logger:expr, $span:expr, $func:expr) => {{ + use opentelemetry::trace::TraceContextExt; + + let span = $span.start($logger.tracer()); + let cx = opentelemetry::Context::current_with_span(span); + let guard = cx.clone().attach(); + let t = $func; + + if let Err(e) = &t { + cx.span().record_error(e); + } + + std::mem::drop(guard); + + t + }}; +} + +#[macro_export] +macro_rules! spanf { + ($logger:expr, $span:expr, $func:expr) => {{ + use opentelemetry::trace::{FutureExt, TraceContextExt}; + + let span = $span.start($logger.tracer()); + let cx = opentelemetry::Context::current_with_span(span); + let t = $func.with_context(cx.clone()).await; + + if let Err(e) = &t { + cx.span().record_error(e); + } + + cx.span().end(); + + t + }}; +} diff --git a/cli/src/options.rs b/cli/src/options.rs new file mode 100644 index 00000000000..4493c244e8d --- /dev/null +++ b/cli/src/options.rs @@ -0,0 +1,112 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::fmt; + +use serde::{Deserialize, Serialize}; + +#[derive(clap::ArgEnum, Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub enum Quality { + #[serde(rename = "stable")] + Stable, + #[serde(rename = "exploration")] + Exploration, + #[serde(other)] + Insiders, +} + +impl Quality { + /// Lowercased name in paths and protocol + pub fn get_machine_name(&self) -> &'static str { + match self { + Quality::Insiders => "insiders", + Quality::Exploration => "exploration", + Quality::Stable => "stable", + } + } + + /// Uppercased display name for humans + pub fn get_capitalized_name(&self) -> &'static str { + match self { + Quality::Insiders => "Insiders", + Quality::Exploration => "Exploration", + Quality::Stable => "Stable", + } + } + + pub fn get_macos_app_name(&self) -> &'static str { + match self { + Quality::Insiders => "Visual Studio Code - Insiders", + Quality::Exploration => "Visual Studio Code - Exploration", + Quality::Stable => "Visual Studio Code", + } + } + + pub fn get_commandline_name(&self) -> &'static str { + match self { + Quality::Insiders => "code-insiders", + Quality::Exploration => "code-exploration", + Quality::Stable => "code", + } + } + + #[cfg(target_os = "windows")] + pub fn server_entrypoint(&self) -> &'static str { + match self { + Quality::Insiders => "code-server-insiders.cmd", + Quality::Exploration => "code-server-exploration.cmd", + Quality::Stable => "code-server.cmd", + } + } + #[cfg(not(target_os = "windows"))] + pub fn server_entrypoint(&self) -> &'static str { + match self { + Quality::Insiders => "code-server-insiders", + Quality::Exploration => "code-server-exploration", + Quality::Stable => "code-server", + } + } +} + +impl fmt::Display for Quality { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.get_capitalized_name()) + } +} + +impl TryFrom<&str> for Quality { + type Error = String; + + fn try_from(s: &str) -> Result { + match s { + "stable" => Ok(Quality::Stable), + "insiders" | "insider" => Ok(Quality::Insiders), + "exploration" => Ok(Quality::Exploration), + _ => Err(format!( + "Unknown quality: {}. Must be one of stable, insiders, or exploration.", + s + )), + } + } +} + +#[derive(clap::ArgEnum, Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum TelemetryLevel { + Off, + Crash, + Error, + All, +} + +impl fmt::Display for TelemetryLevel { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TelemetryLevel::Off => write!(f, "off"), + TelemetryLevel::Crash => write!(f, "crash"), + TelemetryLevel::Error => write!(f, "error"), + TelemetryLevel::All => write!(f, "all"), + } + } +} diff --git a/cli/src/self_update.rs b/cli/src/self_update.rs new file mode 100644 index 00000000000..3ea8274b338 --- /dev/null +++ b/cli/src/self_update.rs @@ -0,0 +1,163 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::{fs, path::Path, process::Command}; +use tempfile::tempdir; + +use crate::{ + constants::{VSCODE_CLI_COMMIT, VSCODE_CLI_QUALITY}, + options::Quality, + update_service::{unzip_downloaded_release, Platform, Release, TargetKind, UpdateService}, + util::{ + errors::{wrap, AnyError, CorruptDownload, UpdatesNotConfigured}, + http, + io::{ReportCopyProgress, SilentCopyProgress}, + }, +}; + +pub struct SelfUpdate<'a> { + commit: &'static str, + quality: Quality, + platform: Platform, + update_service: &'a UpdateService, +} + +impl<'a> SelfUpdate<'a> { + pub fn new(update_service: &'a UpdateService) -> Result { + let commit = VSCODE_CLI_COMMIT + .ok_or_else(|| UpdatesNotConfigured("unknown build commit".to_string()))?; + + let quality = VSCODE_CLI_QUALITY + .ok_or_else(|| UpdatesNotConfigured("no configured quality".to_string())) + .and_then(|q| Quality::try_from(q).map_err(UpdatesNotConfigured))?; + + let platform = Platform::env_default().ok_or_else(|| { + UpdatesNotConfigured("Unknown platform, please report this error".to_string()) + })?; + + Ok(Self { + commit, + quality, + platform, + update_service, + }) + } + + /// Gets the current release + pub async fn get_current_release(&self) -> Result { + self.update_service + .get_latest_commit(self.platform, TargetKind::Cli, self.quality) + .await + } + + /// Gets whether the given release is what this CLI is built against + pub fn is_up_to_date_with(&self, release: &Release) -> bool { + release.commit == self.commit + } + + /// Updates the CLI to the given release. + pub async fn do_update( + &self, + release: &Release, + progress: impl ReportCopyProgress, + ) -> Result<(), AnyError> { + // 1. Download the archive into a temporary directory + let tempdir = tempdir().map_err(|e| wrap(e, "Failed to create temp dir"))?; + let archive_path = tempdir.path().join("archive"); + let stream = self.update_service.get_download_stream(release).await?; + http::download_into_file(&archive_path, progress, stream).await?; + + // 2. Unzip the archive and get the binary + let target_path = + std::env::current_exe().map_err(|e| wrap(e, "could not get current exe"))?; + let staging_path = target_path.with_extension(".update"); + let archive_contents_path = tempdir.path().join("content"); + // unzipping the single binary is pretty small and fast--don't bother with passing progress + unzip_downloaded_release(&archive_path, &archive_contents_path, SilentCopyProgress())?; + copy_updated_cli_to_path(&archive_contents_path, &staging_path)?; + + // 3. Copy file metadata, make sure the new binary is executable\ + copy_file_metadata(&target_path, &staging_path) + .map_err(|e| wrap(e, "failed to set file permissions"))?; + validate_cli_is_good(&staging_path)?; + + // Try to rename the old CLI to the tempdir, where it can get cleaned up by the + // OS later. However, this can fail if the tempdir is on a different drive + // than the installation dir. In this case just rename it to ".old". + if fs::rename(&target_path, &tempdir.path().join("old-code-cli")).is_err() { + fs::rename(&target_path, &target_path.with_extension(".old")) + .map_err(|e| wrap(e, "failed to rename old CLI"))?; + } + + fs::rename(&staging_path, &target_path) + .map_err(|e| wrap(e, "failed to rename newly installed CLI"))?; + + Ok(()) + } +} + +fn validate_cli_is_good(exe_path: &Path) -> Result<(), AnyError> { + let o = Command::new(exe_path) + .args(["--version"]) + .output() + .map_err(|e| CorruptDownload(format!("could not execute new binary, aborting: {}", e)))?; + + if !o.status.success() { + let msg = format!( + "could not execute new binary, aborting. Stdout:\r\n\r\n{}\r\n\r\nStderr:\r\n\r\n{}", + String::from_utf8_lossy(&o.stdout), + String::from_utf8_lossy(&o.stderr), + ); + + return Err(CorruptDownload(msg).into()); + } + + Ok(()) +} + +fn copy_updated_cli_to_path(unzipped_content: &Path, staging_path: &Path) -> Result<(), AnyError> { + let unzipped_files = fs::read_dir(unzipped_content) + .map_err(|e| wrap(e, "could not read update contents"))? + .collect::>(); + if unzipped_files.len() != 1 { + let msg = format!( + "expected exactly one file in update, got {}", + unzipped_files.len() + ); + return Err(CorruptDownload(msg).into()); + } + + let archive_file = unzipped_files[0] + .as_ref() + .map_err(|e| wrap(e, "error listing update files"))?; + fs::copy(&archive_file.path(), staging_path) + .map_err(|e| wrap(e, "error copying to staging file"))?; + Ok(()) +} + +#[cfg(target_os = "windows")] +fn copy_file_metadata(from: &Path, to: &Path) -> Result<(), std::io::Error> { + let permissions = from.metadata()?.permissions(); + fs::set_permissions(&to, permissions)?; + Ok(()) +} + +#[cfg(not(target_os = "windows"))] +fn copy_file_metadata(from: &Path, to: &Path) -> Result<(), std::io::Error> { + use std::os::unix::ffi::OsStrExt; + use std::os::unix::fs::MetadataExt; + + let metadata = from.metadata()?; + fs::set_permissions(&to, metadata.permissions())?; + + // based on coreutils' chown https://github.com/uutils/coreutils/blob/72b4629916abe0852ad27286f4e307fbca546b6e/src/chown/chown.rs#L266-L281 + let s = std::ffi::CString::new(to.as_os_str().as_bytes()).unwrap(); + let ret = unsafe { libc::chown(s.as_ptr(), metadata.uid(), metadata.gid()) }; + if ret != 0 { + return Err(std::io::Error::last_os_error()); + } + + Ok(()) +} diff --git a/cli/src/state.rs b/cli/src/state.rs new file mode 100644 index 00000000000..1a33ea755f8 --- /dev/null +++ b/cli/src/state.rs @@ -0,0 +1,152 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +extern crate dirs; + +use std::{ + fs::{create_dir, read_to_string, remove_dir_all, write}, + path::{Path, PathBuf}, + sync::{Arc, Mutex}, +}; + +use serde::{de::DeserializeOwned, Serialize}; + +use crate::util::errors::{wrap, AnyError, NoHomeForLauncherError, WrappedError}; + +const HOME_DIR_ALTS: [&str; 2] = ["$HOME", "~"]; + +#[derive(Clone)] +pub struct LauncherPaths { + root: PathBuf, +} + +struct PersistedStateContainer +where + T: Clone + Serialize + DeserializeOwned + Default, +{ + path: PathBuf, + state: Option, +} + +impl PersistedStateContainer +where + T: Clone + Serialize + DeserializeOwned + Default, +{ + fn load_or_get(&mut self) -> T { + if let Some(state) = &self.state { + return state.clone(); + } + + let state = if let Ok(s) = read_to_string(&self.path) { + serde_json::from_str::(&s).unwrap_or_default() + } else { + T::default() + }; + + self.state = Some(state.clone()); + state + } + + fn save(&mut self, state: T) -> Result<(), WrappedError> { + let s = serde_json::to_string(&state).unwrap(); + self.state = Some(state); + write(&self.path, s).map_err(|e| { + wrap( + e, + format!("error saving launcher state into {}", self.path.display()), + ) + }) + } +} + +/// Container that holds some state value that is persisted to disk. +#[derive(Clone)] +pub struct PersistedState +where + T: Clone + Serialize + DeserializeOwned + Default, +{ + container: Arc>>, +} + +impl PersistedState +where + T: Clone + Serialize + DeserializeOwned + Default, +{ + /// Creates a new state container that persists to the given path. + pub fn new(path: PathBuf) -> PersistedState { + PersistedState { + container: Arc::new(Mutex::new(PersistedStateContainer { path, state: None })), + } + } + + /// Loads persisted state. + pub fn load(&self) -> T { + self.container.lock().unwrap().load_or_get() + } + + /// Saves persisted state. + pub fn save(&self, state: T) -> Result<(), WrappedError> { + self.container.lock().unwrap().save(state) + } + + /// Mutates persisted state. + pub fn update_with( + &self, + v: V, + mutator: fn(v: V, state: &mut T) -> R, + ) -> Result { + let mut container = self.container.lock().unwrap(); + let mut state = container.load_or_get(); + let r = mutator(v, &mut state); + container.save(state).map(|_| r) + } +} + +impl LauncherPaths { + pub fn new(root: &Option) -> Result { + let root = root.as_deref().unwrap_or("~/.vscode-cli"); + let mut replaced = root.to_owned(); + for token in HOME_DIR_ALTS { + if root.contains(token) { + if let Some(home) = dirs::home_dir() { + replaced = root.replace(token, &home.to_string_lossy()) + } else { + return Err(AnyError::from(NoHomeForLauncherError())); + } + } + } + + if !Path::new(&replaced).exists() { + create_dir(&replaced) + .map_err(|e| wrap(e, format!("error creating directory {}", &replaced)))?; + } + + Ok(LauncherPaths::new_without_replacements(PathBuf::from( + replaced, + ))) + } + + pub fn new_without_replacements(root: PathBuf) -> LauncherPaths { + LauncherPaths { root } + } + + /// Root directory for the server launcher + pub fn root(&self) -> &Path { + &self.root + } + + /// Removes the launcher data directory. + pub fn remove(&self) -> Result<(), WrappedError> { + remove_dir_all(&self.root).map_err(|e| { + wrap( + e, + format!( + "error removing launcher data directory {}", + self.root.display() + ), + ) + }) + } +} diff --git a/cli/src/tunnels.rs b/cli/src/tunnels.rs new file mode 100644 index 00000000000..d94e47addf3 --- /dev/null +++ b/cli/src/tunnels.rs @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +pub mod code_server; +pub mod dev_tunnels; +pub mod legal; +pub mod paths; + +mod control_server; +mod name_generator; +mod port_forwarder; +mod protocol; +#[cfg_attr(unix, path = "tunnels/server_bridge_unix.rs")] +#[cfg_attr(windows, path = "tunnels/server_bridge_windows.rs")] +mod server_bridge; +mod service; +#[cfg(target_os = "windows")] +mod service_windows; + +pub use control_server::serve; +pub use service::{ + create_service_manager, ServiceContainer, ServiceManager, SERVICE_LOG_FILE_NAME, +}; diff --git a/cli/src/tunnels/code_server.rs b/cli/src/tunnels/code_server.rs new file mode 100644 index 00000000000..559f5e075f6 --- /dev/null +++ b/cli/src/tunnels/code_server.rs @@ -0,0 +1,757 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use super::paths::{InstalledServer, LastUsedServers, ServerPaths}; +use crate::options::{Quality, TelemetryLevel}; +use crate::state::LauncherPaths; +use crate::update_service::{ + unzip_downloaded_release, Platform, Release, TargetKind, UpdateService, +}; +use crate::util::command::{capture_command, kill_tree}; +use crate::util::errors::{ + wrap, AnyError, ExtensionInstallFailed, MissingEntrypointError, WrappedError, +}; +use crate::util::http; +use crate::util::io::SilentCopyProgress; +use crate::util::machine::process_exists; +use crate::{debug, info, log, span, spanf, trace, warning}; +use lazy_static::lazy_static; +use opentelemetry::KeyValue; +use regex::Regex; +use serde::Deserialize; +use std::fs; +use std::fs::File; +use std::io::{ErrorKind, Write}; +use std::path::{Path, PathBuf}; +use std::time::Duration; +use tokio::fs::remove_file; +use tokio::io::{AsyncBufReadExt, BufReader}; +use tokio::process::{Child, Command}; +use tokio::sync::oneshot::Receiver; +use tokio::time::{interval, timeout}; +use uuid::Uuid; + +lazy_static! { + static ref LISTENING_PORT_RE: Regex = + Regex::new(r"Extension host agent listening on (.+)").unwrap(); + static ref WEB_UI_RE: Regex = Regex::new(r"Web UI available at (.+)").unwrap(); +} + +const MAX_RETAINED_SERVERS: usize = 5; + +#[derive(Clone, Debug, Default)] +pub struct CodeServerArgs { + pub host: Option, + pub port: Option, + pub socket_path: Option, + + // common argument + pub telemetry_level: Option, + pub log: Option, + pub accept_server_license_terms: bool, + pub verbose: bool, + // extension management + pub install_extensions: Vec, + pub uninstall_extensions: Vec, + pub list_extensions: bool, + pub show_versions: bool, + pub category: Option, + pub pre_release: bool, + pub force: bool, + pub start_server: bool, + // connection tokens + pub connection_token: Option, + pub connection_token_file: Option, + pub without_connection_token: bool, +} + +impl CodeServerArgs { + pub fn log_level(&self) -> log::Level { + if self.verbose { + log::Level::Trace + } else { + self.log.unwrap_or(log::Level::Info) + } + } + + pub fn telemetry_disabled(&self) -> bool { + self.telemetry_level == Some(TelemetryLevel::Off) + } + + pub fn command_arguments(&self) -> Vec { + let mut args = Vec::new(); + if let Some(i) = &self.socket_path { + args.push(format!("--socket-path={}", i)); + } else { + if let Some(i) = &self.host { + args.push(format!("--host={}", i)); + } + if let Some(i) = &self.port { + args.push(format!("--port={}", i)); + } + } + + if let Some(i) = &self.connection_token { + args.push(format!("--connection-token={}", i)); + } + if let Some(i) = &self.connection_token_file { + args.push(format!("--connection-token-file={}", i)); + } + if self.without_connection_token { + args.push(String::from("--without-connection-token")); + } + if self.accept_server_license_terms { + args.push(String::from("--accept-server-license-terms")); + } + if let Some(i) = self.telemetry_level { + args.push(format!("--telemetry-level={}", i)); + } + if let Some(i) = self.log { + args.push(format!("--log={}", i)); + } + + for extension in &self.install_extensions { + args.push(format!("--install-extension={}", extension)); + } + if !&self.install_extensions.is_empty() { + if self.pre_release { + args.push(String::from("--pre-release")); + } + if self.force { + args.push(String::from("--force")); + } + } + for extension in &self.uninstall_extensions { + args.push(format!("--uninstall-extension={}", extension)); + } + if self.list_extensions { + args.push(String::from("--list-extensions")); + if self.show_versions { + args.push(String::from("--show-versions")); + } + if let Some(i) = &self.category { + args.push(format!("--category={}", i)); + } + } + if self.start_server { + args.push(String::from("--start-server")); + } + args + } +} + +/// Base server params that can be `resolve()`d to a `ResolvedServerParams`. +/// Doing so fetches additional information like a commit ID if previously +/// unspecified. +pub struct ServerParamsRaw { + pub commit_id: Option, + pub quality: Quality, + pub code_server_args: CodeServerArgs, + pub headless: bool, + pub platform: Platform, +} + +/// Server params that can be used to start a VS Code server. +pub struct ResolvedServerParams { + pub release: Release, + pub code_server_args: CodeServerArgs, +} + +impl ResolvedServerParams { + fn as_installed_server(&self) -> InstalledServer { + InstalledServer { + commit: self.release.commit.clone(), + quality: self.release.quality, + headless: self.release.target == TargetKind::Server, + } + } +} + +impl ServerParamsRaw { + pub async fn resolve(self, log: &log::Logger) -> Result { + Ok(ResolvedServerParams { + release: self.get_or_fetch_commit_id(log).await?, + code_server_args: self.code_server_args, + }) + } + + async fn get_or_fetch_commit_id(&self, log: &log::Logger) -> Result { + let target = match self.headless { + true => TargetKind::Server, + false => TargetKind::Web, + }; + + if let Some(c) = &self.commit_id { + return Ok(Release { + commit: c.clone(), + quality: self.quality, + target, + name: String::new(), + platform: self.platform, + }); + } + + UpdateService::new(log.clone(), reqwest::Client::new()) + .get_latest_commit(self.platform, target, self.quality) + .await + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(dead_code)] +struct UpdateServerVersion { + pub name: String, + pub version: String, + pub product_version: String, + pub timestamp: i64, +} + +/// Code server listening on a port address. +pub struct SocketCodeServer { + pub commit_id: String, + pub socket: PathBuf, + pub origin: CodeServerOrigin, +} + +/// Code server listening on a socket address. +pub struct PortCodeServer { + pub commit_id: String, + pub port: u16, + pub origin: CodeServerOrigin, +} + +/// A server listening on any address/location. +pub enum AnyCodeServer { + Socket(SocketCodeServer), + Port(PortCodeServer), +} + +// impl AnyCodeServer { +// pub fn origin(&mut self) -> &mut CodeServerOrigin { +// match self { +// AnyCodeServer::Socket(p) => &mut p.origin, +// AnyCodeServer::Port(p) => &mut p.origin, +// } +// } +// } + +pub enum CodeServerOrigin { + /// A new code server, that opens the barrier when it exits. + New(Box), + /// An existing code server with a PID. + Existing(u32), +} + +impl CodeServerOrigin { + pub async fn wait_for_exit(&mut self) { + match self { + CodeServerOrigin::New(child) => { + child.wait().await.ok(); + } + CodeServerOrigin::Existing(pid) => { + let mut interval = interval(Duration::from_secs(30)); + while process_exists(*pid) { + interval.tick().await; + } + } + } + } + + pub async fn kill(&mut self) { + match self { + CodeServerOrigin::New(child) => { + child.kill().await.ok(); + } + CodeServerOrigin::Existing(pid) => { + kill_tree(*pid).await.ok(); + } + } + } +} + +async fn check_and_create_dir(path: &Path) -> Result<(), WrappedError> { + tokio::fs::create_dir_all(path) + .await + .map_err(|e| wrap(e, "error creating server directory"))?; + Ok(()) +} + +async fn install_server_if_needed( + log: &log::Logger, + paths: &ServerPaths, + release: &Release, +) -> Result<(), AnyError> { + if paths.executable.exists() { + info!( + log, + "Found existing installation at {}", + paths.server_dir.display() + ); + return Ok(()); + } + + let tar_file_path = spanf!( + log, + log.span("server.download"), + download_server(&paths.server_dir, release, log) + )?; + + span!( + log, + log.span("server.extract"), + install_server(&tar_file_path, paths, log) + )?; + + Ok(()) +} + +async fn download_server( + path: &Path, + release: &Release, + log: &log::Logger, +) -> Result { + let response = UpdateService::new(log.clone(), reqwest::Client::new()) + .get_download_stream(release) + .await?; + + let mut save_path = path.to_owned(); + + let fname = response + .url() + .path_segments() + .and_then(|segments| segments.last()) + .and_then(|name| if name.is_empty() { None } else { Some(name) }) + .unwrap_or("tmp.zip"); + + info!( + log, + "Downloading VS Code server {} -> {}", + response.url(), + save_path.display() + ); + + save_path.push(fname); + http::download_into_file( + &save_path, + log.get_download_logger("server download progress:"), + response, + ) + .await?; + + Ok(save_path) +} + +fn install_server( + compressed_file: &Path, + paths: &ServerPaths, + log: &log::Logger, +) -> Result<(), AnyError> { + info!(log, "Setting up server..."); + + unzip_downloaded_release(compressed_file, &paths.server_dir, SilentCopyProgress())?; + + match fs::remove_file(&compressed_file) { + Ok(()) => {} + Err(e) => { + if e.kind() != ErrorKind::NotFound { + return Err(AnyError::from(wrap(e, "error removing downloaded file"))); + } + } + } + + if !paths.executable.exists() { + return Err(AnyError::from(MissingEntrypointError())); + } + + Ok(()) +} + +/// Ensures the given list of extensions are installed on the running server. +async fn do_extension_install_on_running_server( + start_script_path: &Path, + extensions: &[String], + log: &log::Logger, +) -> Result<(), AnyError> { + if extensions.is_empty() { + return Ok(()); + } + + debug!(log, "Installing extensions..."); + let command = format!( + "{} {}", + start_script_path.display(), + extensions + .iter() + .map(|s| get_extensions_flag(s)) + .collect::>() + .join(" ") + ); + + let result = capture_command("bash", &["-c", &command]).await?; + if !result.status.success() { + Err(AnyError::from(ExtensionInstallFailed( + String::from_utf8_lossy(&result.stderr).to_string(), + ))) + } else { + Ok(()) + } +} + +pub struct ServerBuilder<'a> { + logger: &'a log::Logger, + server_params: &'a ResolvedServerParams, + last_used: LastUsedServers<'a>, + server_paths: ServerPaths, +} + +impl<'a> ServerBuilder<'a> { + pub fn new( + logger: &'a log::Logger, + server_params: &'a ResolvedServerParams, + launcher_paths: &'a LauncherPaths, + ) -> Self { + Self { + logger, + server_params, + last_used: LastUsedServers::new(launcher_paths), + server_paths: server_params + .as_installed_server() + .server_paths(launcher_paths), + } + } + + /// Gets any already-running server from this directory. + pub async fn get_running(&self) -> Result, AnyError> { + info!( + self.logger, + "Checking {} and {} for a running server...", + self.server_paths.logfile.display(), + self.server_paths.pidfile.display() + ); + + let pid = match self.server_paths.get_running_pid() { + Some(pid) => pid, + None => return Ok(None), + }; + info!(self.logger, "Found running server (pid={})", pid); + if !Path::new(&self.server_paths.logfile).exists() { + warning!(self.logger, "VS Code Server is running but its logfile is missing. Don't delete the VS Code Server manually, run the command 'code-server prune'."); + return Ok(None); + } + + do_extension_install_on_running_server( + &self.server_paths.executable, + &self.server_params.code_server_args.install_extensions, + self.logger, + ) + .await?; + + let origin = CodeServerOrigin::Existing(pid); + let contents = fs::read_to_string(&self.server_paths.logfile) + .expect("Something went wrong reading log file"); + + if let Some(port) = parse_port_from(&contents) { + Ok(Some(AnyCodeServer::Port(PortCodeServer { + commit_id: self.server_params.release.commit.to_owned(), + port, + origin, + }))) + } else if let Some(socket) = parse_socket_from(&contents) { + Ok(Some(AnyCodeServer::Socket(SocketCodeServer { + commit_id: self.server_params.release.commit.to_owned(), + socket, + origin, + }))) + } else { + Ok(None) + } + } + + /// Ensures the server is set up in the configured directory. + pub async fn setup(&self) -> Result<(), AnyError> { + debug!(self.logger, "Installing and setting up VS Code Server..."); + check_and_create_dir(&self.server_paths.server_dir).await?; + install_server_if_needed(self.logger, &self.server_paths, &self.server_params.release) + .await?; + debug!(self.logger, "Server setup complete"); + + match self.last_used.add(self.server_params.as_installed_server()) { + Err(e) => warning!(self.logger, "Error adding server to last used: {}", e), + Ok(count) if count > MAX_RETAINED_SERVERS => { + if let Err(e) = self.last_used.trim(self.logger, MAX_RETAINED_SERVERS) { + warning!(self.logger, "Error trimming old servers: {}", e); + } + } + Ok(_) => {} + } + + Ok(()) + } + + pub async fn listen_on_default_socket(&self) -> Result { + let requested_file = if cfg!(target_os = "windows") { + PathBuf::from(format!(r"\\.\pipe\vscode-server-{}", Uuid::new_v4())) + } else { + std::env::temp_dir().join(format!("vscode-server-{}", Uuid::new_v4())) + }; + + self.listen_on_socket(&requested_file).await + } + + pub async fn listen_on_socket(&self, socket: &Path) -> Result { + Ok(spanf!( + self.logger, + self.logger.span("server.start").with_attributes(vec! { + KeyValue::new("commit_id", self.server_params.release.commit.to_string()), + KeyValue::new("quality", format!("{}", self.server_params.release.quality)), + }), + self._listen_on_socket(socket) + )?) + } + + async fn _listen_on_socket(&self, socket: &Path) -> Result { + remove_file(&socket).await.ok(); // ignore any error if it doesn't exist + + let mut cmd = self.get_base_command(); + cmd.arg("--start-server") + .arg("--without-connection-token") + .arg("--enable-remote-auto-shutdown") + .arg(format!("--socket-path={}", socket.display())); + + let child = self.spawn_server_process(cmd)?; + let log_file = self.get_logfile()?; + let plog = self.logger.prefixed(&log::new_code_server_prefix()); + + let (mut origin, listen_rx) = + monitor_server::(child, Some(log_file), plog, false); + + let socket = match timeout(Duration::from_secs(8), listen_rx).await { + Err(e) => { + origin.kill().await; + Err(wrap(e, "timed out looking for socket")) + } + Ok(Err(e)) => { + origin.kill().await; + Err(wrap(e, "server exited without writing socket")) + } + Ok(Ok(socket)) => Ok(socket), + }?; + + info!(self.logger, "Server started"); + + Ok(SocketCodeServer { + commit_id: self.server_params.release.commit.to_owned(), + socket, + origin, + }) + } + + /// Starts with a given opaque set of args. Does not set up any port or + /// socket, but does return one if present, in the form of a channel. + pub async fn start_opaque_with_args( + &self, + args: &[String], + ) -> Result<(CodeServerOrigin, Receiver), AnyError> + where + M: ServerOutputMatcher, + R: 'static + Send + std::fmt::Debug, + { + let mut cmd = self.get_base_command(); + cmd.args(args); + + let child = self.spawn_server_process(cmd)?; + let plog = self.logger.prefixed(&log::new_code_server_prefix()); + + Ok(monitor_server::(child, None, plog, true)) + } + + fn spawn_server_process(&self, mut cmd: Command) -> Result { + info!(self.logger, "Starting server..."); + + debug!(self.logger, "Starting server with command... {:?}", cmd); + + let child = cmd + .stderr(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .spawn() + .map_err(|e| wrap(e, "error spawning server"))?; + + self.server_paths + .write_pid(child.id().expect("expected server to have pid"))?; + + Ok(child) + } + + fn get_logfile(&self) -> Result { + File::create(&self.server_paths.logfile).map_err(|e| { + wrap( + e, + format!( + "error creating log file {}", + self.server_paths.logfile.display() + ), + ) + }) + } + + fn get_base_command(&self) -> Command { + let mut cmd = Command::new(&self.server_paths.executable); + cmd.stdin(std::process::Stdio::null()) + .args(self.server_params.code_server_args.command_arguments()); + cmd + } +} + +fn monitor_server( + mut child: Child, + log_file: Option, + plog: log::Logger, + write_directly: bool, +) -> (CodeServerOrigin, Receiver) +where + M: ServerOutputMatcher, + R: 'static + Send + std::fmt::Debug, +{ + let stdout = child + .stdout + .take() + .expect("child did not have a handle to stdout"); + + let stderr = child + .stderr + .take() + .expect("child did not have a handle to stdout"); + + let (listen_tx, listen_rx) = tokio::sync::oneshot::channel(); + + // Handle stderr and stdout in a separate task. Initially scan lines looking + // for the listening port. Afterwards, just scan and write out to the file. + tokio::spawn(async move { + let mut stdout_reader = BufReader::new(stdout).lines(); + let mut stderr_reader = BufReader::new(stderr).lines(); + let write_line = |line: &str| -> std::io::Result<()> { + if let Some(mut f) = log_file.as_ref() { + f.write_all(line.as_bytes())?; + f.write_all(&[b'\n'])?; + } + if write_directly { + println!("{}", line); + } else { + trace!(plog, line); + } + Ok(()) + }; + + loop { + let line = tokio::select! { + l = stderr_reader.next_line() => l, + l = stdout_reader.next_line() => l, + }; + + match line { + Err(e) => { + trace!(plog, "error reading from stdout/stderr: {}", e); + return; + } + Ok(None) => break, + Ok(Some(l)) => { + write_line(&l).ok(); + + if let Some(listen_on) = M::match_line(&l) { + trace!(plog, "parsed location: {:?}", listen_on); + listen_tx.send(listen_on).ok(); + break; + } + } + } + } + + loop { + let line = tokio::select! { + l = stderr_reader.next_line() => l, + l = stdout_reader.next_line() => l, + }; + + match line { + Err(e) => { + trace!(plog, "error reading from stdout/stderr: {}", e); + break; + } + Ok(None) => break, + Ok(Some(l)) => { + write_line(&l).ok(); + } + } + } + }); + + let origin = CodeServerOrigin::New(Box::new(child)); + (origin, listen_rx) +} + +fn get_extensions_flag(extension_id: &str) -> String { + format!("--install-extension={}", extension_id) +} + +/// A type that can be used to scan stdout from the VS Code server. Returns +/// some other type that, in turn, is returned from starting the server. +pub trait ServerOutputMatcher +where + R: Send, +{ + fn match_line(line: &str) -> Option; +} + +/// Parses a line like "Extension host agent listening on /tmp/foo.sock" +struct SocketMatcher(); + +impl ServerOutputMatcher for SocketMatcher { + fn match_line(line: &str) -> Option { + parse_socket_from(line) + } +} + +/// Parses a line like "Extension host agent listening on 9000" +pub struct PortMatcher(); + +impl ServerOutputMatcher for PortMatcher { + fn match_line(line: &str) -> Option { + parse_port_from(line) + } +} + +/// Parses a line like "Web UI available at http://localhost:9000/?tkn=..." +pub struct WebUiMatcher(); + +impl ServerOutputMatcher for WebUiMatcher { + fn match_line(line: &str) -> Option { + WEB_UI_RE.captures(line).and_then(|cap| { + cap.get(1) + .and_then(|uri| reqwest::Url::parse(uri.as_str()).ok()) + }) + } +} + +/// Does not do any parsing and just immediately returns an empty result. +pub struct NoOpMatcher(); + +impl ServerOutputMatcher<()> for NoOpMatcher { + fn match_line(_: &str) -> Option<()> { + Some(()) + } +} + +fn parse_socket_from(text: &str) -> Option { + LISTENING_PORT_RE + .captures(text) + .and_then(|cap| cap.get(1).map(|path| PathBuf::from(path.as_str()))) +} + +fn parse_port_from(text: &str) -> Option { + LISTENING_PORT_RE.captures(text).and_then(|cap| { + cap.get(1) + .and_then(|path| path.as_str().parse::().ok()) + }) +} diff --git a/cli/src/tunnels/control_server.rs b/cli/src/tunnels/control_server.rs new file mode 100644 index 00000000000..e106510ae66 --- /dev/null +++ b/cli/src/tunnels/control_server.rs @@ -0,0 +1,722 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use crate::commands::tunnels::ShutdownSignal; +use crate::constants::{CONTROL_PORT, PROTOCOL_VERSION, VSCODE_CLI_VERSION}; +use crate::log; +use crate::self_update::SelfUpdate; +use crate::state::LauncherPaths; +use crate::update_service::{Platform, UpdateService}; +use crate::util::errors::{ + wrap, AnyError, MismatchedLaunchModeError, NoAttachedServerError, ServerWriteError, +}; +use crate::util::io::SilentCopyProgress; +use crate::util::sync::{new_barrier, Barrier}; +use opentelemetry::trace::SpanKind; +use opentelemetry::KeyValue; +use serde::Serialize; +use std::convert::Infallible; +use std::env; +use std::path::PathBuf; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::time::Instant; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader}; +use tokio::pin; +use tokio::sync::{mpsc, Mutex}; + +use super::code_server::{ + AnyCodeServer, CodeServerArgs, ServerBuilder, ServerParamsRaw, SocketCodeServer, +}; +use super::dev_tunnels::ActiveTunnel; +use super::paths::prune_stopped_servers; +use super::port_forwarder::{PortForwarding, PortForwardingProcessor}; +use super::protocol::{ + CallServerHttpParams, CallServerHttpResult, ClientRequestMethod, EmptyResult, ErrorResponse, + ForwardParams, ForwardResult, GetHostnameResponse, RefServerMessageParams, ResponseError, + ServeParams, ServerLog, ServerMessageParams, ServerRequestMethod, SuccessResponse, + ToClientRequest, ToServerRequest, UnforwardParams, UpdateParams, UpdateResult, VersionParams, +}; +use super::server_bridge::{get_socket_rw_stream, FromServerMessage, ServerBridge}; + +type ServerBridgeList = Option>; +type ServerBridgeListLock = Arc>; + +struct HandlerContext { + /// Exit barrier for the socket. + closer: Barrier<()>, + /// Log handle for the server + log: log::Logger, + /// A loopback channel to talk to the TCP server task. + server_tx: mpsc::Sender, + /// A loopback channel to talk to the socket server task. + socket_tx: mpsc::Sender, + /// Configured launcher paths. + launcher_paths: LauncherPaths, + /// Connected VS Code Server + code_server: Option, + /// Potentially many "websocket" connections to client + server_bridges: ServerBridgeListLock, + // the cli arguments used to start the code server + code_server_args: CodeServerArgs, + /// counter for the number of bytes received from the socket + rx_counter: Arc, + /// port forwarding functionality + port_forwarding: PortForwarding, + /// install platform for the VS Code server + platform: Platform, +} + +impl HandlerContext { + async fn dispose(self) { + let bridges: ServerBridgeList = { + let mut lock = self.server_bridges.lock().await; + let bridges = lock.take(); + *lock = None; + bridges + }; + + if let Some(b) = bridges { + for (_, bridge) in b { + if let Err(e) = bridge.close().await { + warning!( + self.log, + "Could not properly dispose of connection context: {}", + e + ) + } else { + debug!(self.log, "Closed server bridge."); + } + } + } + + info!(self.log, "Disposed of connection to running server."); + } +} + +enum ServerSignal { + /// Signalled when the server has been updated and we want to respawn. + /// We'd generally need to stop and then restart the launcher, but the + /// program might be managed by a supervisor like systemd. Instead, we + /// will stop the TCP listener and spawn the launcher again as a subprocess + /// with the same arguments we used. + Respawn, +} + +struct CloseReason(String); + +enum SocketSignal { + /// Signals bytes to send to the socket. + Send(Vec), + /// Closes the socket (e.g. as a result of an error) + CloseWith(CloseReason), + /// Disposes ServerBridge corresponding to an ID + CloseServerBridge(u16), +} + +impl SocketSignal { + fn from_message(msg: &T) -> Self + where + T: Serialize + ?Sized, + { + SocketSignal::Send(rmp_serde::to_vec_named(msg).unwrap()) + } +} + +impl FromServerMessage for SocketSignal { + fn from_server_message(i: u16, body: &[u8]) -> Self { + SocketSignal::from_message(&ToClientRequest { + id: None, + params: ClientRequestMethod::servermsg(RefServerMessageParams { i, body }), + }) + } + + fn from_closed_server_bridge(i: u16) -> Self { + SocketSignal::CloseServerBridge(i) + } +} + +pub struct ServerTermination { + /// Whether the server should be respawned in a new binary (see ServerSignal.Respawn). + pub respawn: bool, + pub tunnel: ActiveTunnel, +} + +fn print_listening(log: &log::Logger, tunnel_name: &str) { + debug!(log, "VS Code Server is listening for incoming connections"); + + let home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("")); + let current_dir = env::current_dir().unwrap_or_else(|_| PathBuf::from("")); + + let dir = if home_dir == current_dir { + PathBuf::from("") + } else { + current_dir + }; + + let mut addr = url::Url::parse("https://insiders.vscode.dev").unwrap(); + { + let mut ps = addr.path_segments_mut().unwrap(); + ps.push("tunnel"); + ps.push(tunnel_name); + for segment in &dir { + let as_str = segment.to_string_lossy(); + if !(as_str.len() == 1 && as_str.starts_with(std::path::MAIN_SEPARATOR)) { + ps.push(as_str.as_ref()); + } + } + } + + let message = &format!("\nOpen this link in your browser {}\n", addr); + log.result(message); +} + +// Runs the launcher server. Exits on a ctrl+c or when requested by a user. +// Note that client connections may not be closed when this returns; use +// `close_all_clients()` on the ServerTermination to make this happen. +pub async fn serve( + log: &log::Logger, + mut tunnel: ActiveTunnel, + launcher_paths: &LauncherPaths, + code_server_args: &CodeServerArgs, + platform: Platform, + shutdown_rx: mpsc::Receiver, +) -> Result { + let mut port = tunnel.add_port_direct(CONTROL_PORT).await?; + print_listening(log, &tunnel.name); + + let mut forwarding = PortForwardingProcessor::new(); + let (tx, mut rx) = mpsc::channel::(4); + let (exit_barrier, signal_exit) = new_barrier(); + + pin!(shutdown_rx); + + loop { + tokio::select! { + Some(r) = shutdown_rx.recv() => { + info!(log, "Shutting down: {}", r ); + drop(signal_exit); + return Ok(ServerTermination { + respawn: false, + tunnel, + }); + }, + c = rx.recv() => { + if let Some(ServerSignal::Respawn) = c { + drop(signal_exit); + return Ok(ServerTermination { + respawn: true, + tunnel, + }); + } + }, + Some(w) = forwarding.recv() => { + forwarding.process(w, &mut tunnel).await; + }, + l = port.recv() => { + let socket = match l { + Some(p) => p, + None => { + warning!(log, "ssh tunnel disposed, tearing down"); + return Ok(ServerTermination { + respawn: false, + tunnel, + }); + } + }; + + let own_log = log.prefixed(&log::new_rpc_prefix()); + let own_tx = tx.clone(); + let own_paths = launcher_paths.clone(); + let own_exit = exit_barrier.clone(); + let own_code_server_args = code_server_args.clone(); + let own_forwarding = forwarding.handle(); + + tokio::spawn(async move { + use opentelemetry::trace::{FutureExt, TraceContextExt}; + + let span = own_log.span("server.socket").with_kind(SpanKind::Consumer).start(own_log.tracer()); + let cx = opentelemetry::Context::current_with_span(span); + let serve_at = Instant::now(); + + debug!(own_log, "Serving new connection"); + + let (writehalf, readhalf) = socket.into_split(); + let stats = process_socket(own_exit, readhalf, writehalf, own_log, own_tx, own_paths, own_code_server_args, own_forwarding, platform).with_context(cx.clone()).await; + + cx.span().add_event( + "socket.bandwidth", + vec![ + KeyValue::new("tx", stats.tx as f64), + KeyValue::new("rx", stats.rx as f64), + KeyValue::new("duration_ms", serve_at.elapsed().as_millis() as f64), + ], + ); + cx.span().end(); + }); + } + } + } +} + +struct SocketStats { + rx: usize, + tx: usize, +} + +#[allow(clippy::too_many_arguments)] // necessary here +async fn process_socket( + mut exit_barrier: Barrier<()>, + readhalf: impl AsyncRead + Send + Unpin + 'static, + mut writehalf: impl AsyncWrite + Unpin, + log: log::Logger, + server_tx: mpsc::Sender, + launcher_paths: LauncherPaths, + code_server_args: CodeServerArgs, + port_forwarding: PortForwarding, + platform: Platform, +) -> SocketStats { + let (socket_tx, mut socket_rx) = mpsc::channel(4); + + let rx_counter = Arc::new(AtomicUsize::new(0)); + + let server_bridges: ServerBridgeListLock = Arc::new(Mutex::new(Some(vec![]))); + let server_bridges_lock = Arc::clone(&server_bridges); + let barrier_ctx = exit_barrier.clone(); + let log_ctx = log.clone(); + let rx_counter_ctx = rx_counter.clone(); + + tokio::spawn(async move { + let mut ctx = HandlerContext { + closer: barrier_ctx, + server_tx, + socket_tx, + log: log_ctx, + launcher_paths, + code_server_args, + rx_counter: rx_counter_ctx, + code_server: None, + server_bridges: server_bridges_lock, + port_forwarding, + platform, + }; + + send_version(&ctx.socket_tx).await; + + if let Err(e) = handle_socket_read(readhalf, &mut ctx).await { + debug!(ctx.log, "closing socket reader: {}", e); + ctx.socket_tx + .send(SocketSignal::CloseWith(CloseReason(format!("{}", e)))) + .await + .ok(); + } + + ctx.dispose().await; + }); + + let mut tx_counter = 0; + + loop { + tokio::select! { + _ = exit_barrier.wait() => { + writehalf.shutdown().await.ok(); + break; + }, + recv = socket_rx.recv() => match recv { + None => break, + Some(message) => match message { + SocketSignal::Send(bytes) => { + tx_counter += bytes.len(); + if let Err(e) = writehalf.write_all(&bytes).await { + debug!(log, "Closing connection: {}", e); + break; + } + } + SocketSignal::CloseWith(reason) => { + debug!(log, "Closing connection: {}", reason.0); + break; + } + SocketSignal::CloseServerBridge(id) => { + let mut lock = server_bridges.lock().await; + match &mut *lock { + Some(bridges) => { + if let Some(index) = bridges.iter().position(|(i, _)| *i == id) { + (*bridges).remove(index as usize); + } + }, + None => {} + } + } + } + } + } + } + + SocketStats { + tx: tx_counter, + rx: rx_counter.load(Ordering::Acquire), + } +} + +async fn send_version(tx: &mpsc::Sender) { + tx.send(SocketSignal::from_message(&ToClientRequest { + id: None, + params: ClientRequestMethod::version(VersionParams { + version: VSCODE_CLI_VERSION.unwrap_or("dev"), + protocol_version: PROTOCOL_VERSION, + }), + })) + .await + .ok(); +} +async fn handle_socket_read( + readhalf: impl AsyncRead + Unpin, + ctx: &mut HandlerContext, +) -> Result<(), std::io::Error> { + let mut socket_reader = BufReader::new(readhalf); + let mut decode_buf = vec![]; + let mut did_update = false; + + let result = loop { + match read_next(&mut socket_reader, ctx, &mut decode_buf, &mut did_update).await { + Ok(false) => break Ok(()), + Ok(true) => { /* continue */ } + Err(e) => break Err(e), + } + }; + + // The connection is now closed, asked to respawn if needed + if did_update { + ctx.server_tx.send(ServerSignal::Respawn).await.ok(); + } + + result +} + +/// Reads and handles the next data packet, returns true if the read loop should continue. +async fn read_next( + socket_reader: &mut BufReader, + ctx: &mut HandlerContext, + decode_buf: &mut Vec, + did_update: &mut bool, +) -> Result { + let msg_length = tokio::select! { + u = socket_reader.read_u32() => u? as usize, + _ = ctx.closer.wait() => return Ok(false), + }; + decode_buf.resize(msg_length, 0); + ctx.rx_counter + .fetch_add(msg_length + 4 /* u32 */, Ordering::Relaxed); + + tokio::select! { + r = socket_reader.read_exact(decode_buf) => r?, + _ = ctx.closer.wait() => return Ok(false), + }; + + let req = match rmp_serde::from_slice::(decode_buf) { + Ok(req) => req, + Err(e) => { + warning!(ctx.log, "Error decoding message: {}", e); + return Ok(true); // not fatal + } + }; + + let log = ctx.log.prefixed( + req.id + .map(|id| format!("[call.{}]", id)) + .as_deref() + .unwrap_or("notify"), + ); + + macro_rules! success { + ($r:expr) => { + req.id + .map(|id| rmp_serde::to_vec_named(&SuccessResponse { id, result: &$r })) + }; + } + + macro_rules! tj { + ($name:expr, $e:expr) => { + match (spanf!( + log, + log.span(&format!("call.{}", $name)) + .with_kind(opentelemetry::trace::SpanKind::Server), + $e + )) { + Ok(r) => success!(r), + Err(e) => { + warning!(log, "error handling call: {:?}", e); + req.id.map(|id| { + rmp_serde::to_vec_named(&ErrorResponse { + id, + error: ResponseError { + code: -1, + message: format!("{:?}", e), + }, + }) + }) + } + } + }; + } + + let response = match req.params { + ServerRequestMethod::ping(_) => success!(EmptyResult {}), + ServerRequestMethod::serve(p) => tj!("serve", handle_serve(ctx, &log, p)), + ServerRequestMethod::prune => tj!("prune", handle_prune(ctx)), + ServerRequestMethod::gethostname(_) => tj!("gethostname", handle_get_hostname()), + ServerRequestMethod::update(p) => tj!("update", async { + let r = handle_update(ctx, &p).await; + if matches!(&r, Ok(u) if u.did_update) { + *did_update = true; + } + r + }), + ServerRequestMethod::servermsg(m) => { + if let Err(e) = handle_server_message(ctx, m).await { + warning!(log, "error handling call: {:?}", e); + } + None + } + ServerRequestMethod::callserverhttp(p) => { + tj!("callserverhttp", handle_call_server_http(ctx, p)) + } + ServerRequestMethod::forward(p) => tj!("forward", handle_forward(ctx, p)), + ServerRequestMethod::unforward(p) => tj!("unforward", handle_unforward(ctx, p)), + }; + + if let Some(Ok(res)) = response { + if ctx.socket_tx.send(SocketSignal::Send(res)).await.is_err() { + return Ok(false); + } + } + + Ok(true) +} + +#[derive(Clone)] +struct ServerOutputSink { + tx: mpsc::Sender, +} + +impl log::LogSink for ServerOutputSink { + fn write_log(&self, level: log::Level, _prefix: &str, message: &str) { + let s = SocketSignal::from_message(&ToClientRequest { + id: None, + params: ClientRequestMethod::serverlog(ServerLog { + line: message, + level: level.to_u8(), + }), + }); + + self.tx.try_send(s).ok(); + } + + fn write_result(&self, _message: &str) {} +} + +async fn handle_serve( + ctx: &mut HandlerContext, + log: &log::Logger, + params: ServeParams, +) -> Result { + let mut code_server_args = ctx.code_server_args.clone(); + + // fill params.extensions into code_server_args.install_extensions + code_server_args + .install_extensions + .extend(params.extensions.into_iter()); + + let resolved = ServerParamsRaw { + commit_id: params.commit_id, + quality: params.quality, + code_server_args, + headless: true, + platform: ctx.platform, + } + .resolve(log) + .await?; + + if ctx.code_server.is_none() { + let install_log = log.tee(ServerOutputSink { + tx: ctx.socket_tx.clone(), + }); + let sb = ServerBuilder::new(&install_log, &resolved, &ctx.launcher_paths); + + let server = match sb.get_running().await? { + Some(AnyCodeServer::Socket(s)) => s, + Some(_) => return Err(AnyError::from(MismatchedLaunchModeError())), + None => { + sb.setup().await?; + sb.listen_on_default_socket().await? + } + }; + + ctx.code_server = Some(server); + } + + attach_server_bridge(ctx, params.socket_id).await?; + Ok(EmptyResult {}) +} + +async fn attach_server_bridge(ctx: &mut HandlerContext, socket_id: u16) -> Result { + let attached_fut = ServerBridge::new( + &ctx.code_server.as_ref().unwrap().socket, + socket_id, + &ctx.socket_tx, + ) + .await; + + match attached_fut { + Ok(a) => { + let mut lock = ctx.server_bridges.lock().await; + match &mut *lock { + Some(server_bridges) => (*server_bridges).push((socket_id, a)), + None => *lock = Some(vec![(socket_id, a)]), + } + trace!(ctx.log, "Attached to server"); + Ok(socket_id) + } + Err(e) => Err(e), + } +} + +async fn handle_server_message( + ctx: &mut HandlerContext, + params: ServerMessageParams, +) -> Result { + let mut lock = ctx.server_bridges.lock().await; + + match &mut *lock { + Some(server_bridges) => { + let matched_bridge = server_bridges.iter_mut().find(|(id, _)| *id == params.i); + + match matched_bridge { + Some((_, sb)) => sb + .write(params.body) + .await + .map_err(|_| AnyError::from(ServerWriteError()))?, + None => return Err(AnyError::from(NoAttachedServerError())), + } + } + None => return Err(AnyError::from(NoAttachedServerError())), + } + + Ok(EmptyResult {}) +} + +async fn handle_prune(ctx: &HandlerContext) -> Result, AnyError> { + prune_stopped_servers(&ctx.launcher_paths).map(|v| { + v.iter() + .map(|p| p.server_dir.display().to_string()) + .collect() + }) +} + +async fn handle_update( + ctx: &HandlerContext, + params: &UpdateParams, +) -> Result { + let update_service = UpdateService::new(ctx.log.clone(), reqwest::Client::new()); + let updater = SelfUpdate::new(&update_service)?; + let latest_release = updater.get_current_release().await?; + let up_to_date = updater.is_up_to_date_with(&latest_release); + + if !params.do_update || up_to_date { + return Ok(UpdateResult { + up_to_date, + did_update: false, + }); + } + + info!(ctx.log, "Updating CLI to {}", latest_release); + + updater + .do_update(&latest_release, SilentCopyProgress()) + .await?; + + Ok(UpdateResult { + up_to_date: true, + did_update: true, + }) +} + +async fn handle_get_hostname() -> Result { + Ok(GetHostnameResponse { + value: gethostname::gethostname().to_string_lossy().into_owned(), + }) +} + +async fn handle_forward( + ctx: &HandlerContext, + params: ForwardParams, +) -> Result { + info!(ctx.log, "Forwarding port {}", params.port); + let uri = ctx.port_forwarding.forward(params.port).await?; + Ok(ForwardResult { uri }) +} + +async fn handle_unforward( + ctx: &HandlerContext, + params: UnforwardParams, +) -> Result { + info!(ctx.log, "Unforwarding port {}", params.port); + ctx.port_forwarding.unforward(params.port).await?; + Ok(EmptyResult {}) +} + +async fn handle_call_server_http( + ctx: &HandlerContext, + params: CallServerHttpParams, +) -> Result { + use hyper::{body, client::conn::Builder, Body, Request}; + + // We use Hyper directly here since reqwest doesn't support sockets/pipes. + // See https://github.com/seanmonstar/reqwest/issues/39 + + let socket = match &ctx.code_server { + Some(cs) => &cs.socket, + None => return Err(AnyError::from(NoAttachedServerError())), + }; + + let rw = get_socket_rw_stream(socket).await?; + + let (mut request_sender, connection) = Builder::new() + .handshake(rw) + .await + .map_err(|e| wrap(e, "error establishing connection"))?; + + // start the connection processing; it's shut down when the sender is dropped + tokio::spawn(connection); + + let mut request_builder = Request::builder() + .method::<&str>(params.method.as_ref()) + .uri(format!("http://127.0.0.1{}", params.path)) + .header("Host", "127.0.0.1"); + + for (k, v) in params.headers { + request_builder = request_builder.header(k, v); + } + let request = request_builder + .body(Body::from(params.body.unwrap_or_default())) + .map_err(|e| wrap(e, "invalid request"))?; + + let response = request_sender + .send_request(request) + .await + .map_err(|e| wrap(e, "error sending request"))?; + + Ok(CallServerHttpResult { + status: response.status().as_u16(), + headers: response + .headers() + .into_iter() + .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())) + .collect(), + body: body::to_bytes(response) + .await + .map_err(|e| wrap(e, "error reading response body"))? + .to_vec(), + }) +} diff --git a/cli/src/tunnels/dev_tunnels.rs b/cli/src/tunnels/dev_tunnels.rs new file mode 100644 index 00000000000..eb362ef8e5b --- /dev/null +++ b/cli/src/tunnels/dev_tunnels.rs @@ -0,0 +1,875 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use crate::auth; +use crate::constants::{CONTROL_PORT, TUNNEL_SERVICE_USER_AGENT}; +use crate::state::{LauncherPaths, PersistedState}; +use crate::util::errors::{ + wrap, AnyError, DevTunnelError, InvalidTunnelName, TunnelCreationFailed, WrappedError, +}; +use crate::util::input::prompt_placeholder; +use crate::{debug, info, log, spanf, trace, warning}; +use async_trait::async_trait; +use futures::TryFutureExt; +use rand::prelude::IteratorRandom; +use regex::Regex; +use reqwest::StatusCode; +use serde::{Deserialize, Serialize}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tokio::sync::{mpsc, watch}; +use tunnels::connections::{ForwardedPortConnection, RelayTunnelHost}; +use tunnels::contracts::{ + Tunnel, TunnelPort, TunnelRelayTunnelEndpoint, PORT_TOKEN, TUNNEL_PROTOCOL_AUTO, +}; +use tunnels::management::{ + new_tunnel_management, HttpError, TunnelLocator, TunnelManagementClient, TunnelRequestOptions, + NO_REQUEST_OPTIONS, +}; + +use super::name_generator; + +#[derive(Clone, Serialize, Deserialize)] +pub struct PersistedTunnel { + pub name: String, + pub id: String, + pub cluster: String, +} + +impl PersistedTunnel { + pub fn into_locator(self) -> TunnelLocator { + TunnelLocator::ID { + cluster: self.cluster, + id: self.id, + } + } + pub fn locator(&self) -> TunnelLocator { + TunnelLocator::ID { + cluster: self.cluster.clone(), + id: self.id.clone(), + } + } +} + +#[async_trait] +trait AccessTokenProvider: Send + Sync { + /// Gets the current access token. + async fn refresh_token(&self) -> Result; +} + +/// Access token provider that provides a fixed token without refreshing. +struct StaticAccessTokenProvider(String); + +impl StaticAccessTokenProvider { + pub fn new(token: String) -> Self { + Self(token) + } +} + +#[async_trait] +impl AccessTokenProvider for StaticAccessTokenProvider { + async fn refresh_token(&self) -> Result { + Ok(self.0.clone()) + } +} + +/// Access token provider that looks up the token from the tunnels API. +struct LookupAccessTokenProvider { + client: TunnelManagementClient, + locator: TunnelLocator, + log: log::Logger, + initial_token: Arc>>, +} + +impl LookupAccessTokenProvider { + pub fn new( + client: TunnelManagementClient, + locator: TunnelLocator, + log: log::Logger, + initial_token: Option, + ) -> Self { + Self { + client, + locator, + log, + initial_token: Arc::new(Mutex::new(initial_token)), + } + } +} + +#[async_trait] +impl AccessTokenProvider for LookupAccessTokenProvider { + async fn refresh_token(&self) -> Result { + if let Some(token) = self.initial_token.lock().unwrap().take() { + return Ok(token); + } + + let tunnel_lookup = spanf!( + self.log, + self.log.span("dev-tunnel.tag.get"), + self.client.get_tunnel( + &self.locator, + &TunnelRequestOptions { + token_scopes: vec!["host".to_string()], + ..Default::default() + } + ) + ); + + trace!(self.log, "Successfully refreshed access token"); + + match tunnel_lookup { + Ok(tunnel) => Ok(get_host_token_from_tunnel(&tunnel)), + Err(e) => Err(wrap(e, "failed to lookup tunnel")), + } + } +} + +#[derive(Clone)] +pub struct DevTunnels { + log: log::Logger, + launcher_tunnel: PersistedState>, + client: TunnelManagementClient, +} + +/// Representation of a tunnel returned from the `start` methods. +pub struct ActiveTunnel { + /// Name of the tunnel + pub name: String, + manager: ActiveTunnelManager, +} + +impl ActiveTunnel { + /// Closes and unregisters the tunnel. + pub async fn close(&mut self) -> Result<(), AnyError> { + self.manager.kill().await?; + Ok(()) + } + + /// Forwards a port to local connections. + pub async fn add_port_direct( + &mut self, + port_number: u16, + ) -> Result, AnyError> { + let port = self.manager.add_port_direct(port_number).await?; + Ok(port) + } + + /// Forwards a port over TCP. + pub async fn add_port_tcp(&mut self, port_number: u16) -> Result<(), AnyError> { + self.manager.add_port_tcp(port_number).await?; + Ok(()) + } + + /// Removes a forwarded port TCP. + pub async fn remove_port(&mut self, port_number: u16) -> Result<(), AnyError> { + self.manager.remove_port(port_number).await?; + Ok(()) + } + + /// Gets the public URI on which a forwarded port can be access in browser. + pub async fn get_port_uri(&mut self, port: u16) -> Result { + let endpoint = self.manager.get_endpoint().await?; + let format = endpoint + .base + .port_uri_format + .expect("expected to have port format"); + + Ok(format.replace(PORT_TOKEN, &port.to_string())) + } +} + +const VSCODE_CLI_TUNNEL_TAG: &str = "vscode-server-launcher"; +const MAX_TUNNEL_NAME_LENGTH: usize = 20; + +fn get_host_token_from_tunnel(tunnel: &Tunnel) -> String { + tunnel + .access_tokens + .as_ref() + .expect("expected to have access tokens") + .get("host") + .expect("expected to have host token") + .to_string() +} + +fn is_valid_name(name: &str) -> Result<(), InvalidTunnelName> { + if name.len() > MAX_TUNNEL_NAME_LENGTH { + return Err(InvalidTunnelName(format!( + "Names cannot be longer than {} characters. Please try a different name.", + MAX_TUNNEL_NAME_LENGTH + ))); + } + + let re = Regex::new(r"^([\w-]+)$").unwrap(); + + if !re.is_match(name) { + return Err(InvalidTunnelName( + "Names can only contain letters, numbers, and '-'. Spaces, commas, and all other special characters are not allowed. Please try a different name.".to_string() + )); + } + + Ok(()) +} + +/// Structure optionally passed into `start_existing_tunnel` to forward an existing tunnel. +#[derive(Clone, Debug)] +pub struct ExistingTunnel { + /// Name you'd like to assign preexisting tunnel to use to connect to the VS Code Server + pub tunnel_name: String, + + /// Token to authenticate and use preexisting tunnel + pub host_token: String, + + /// Id of preexisting tunnel to use to connect to the VS Code Server + pub tunnel_id: String, + + /// Cluster of preexisting tunnel to use to connect to the VS Code Server + pub cluster: String, +} + +impl DevTunnels { + pub fn new(log: &log::Logger, auth: auth::Auth, paths: &LauncherPaths) -> DevTunnels { + let mut client = new_tunnel_management(&TUNNEL_SERVICE_USER_AGENT); + client.authorization_provider(auth); + + DevTunnels { + log: log.clone(), + client: client.into(), + launcher_tunnel: PersistedState::new(paths.root().join("code_tunnel.json")), + } + } + + pub async fn remove_tunnel(&mut self) -> Result<(), AnyError> { + let tunnel = match self.launcher_tunnel.load() { + Some(t) => t, + None => { + return Ok(()); + } + }; + + spanf!( + self.log, + self.log.span("dev-tunnel.delete"), + self.client + .delete_tunnel(&tunnel.into_locator(), NO_REQUEST_OPTIONS) + ) + .map_err(|e| wrap(e, "failed to execute `tunnel delete`"))?; + + self.launcher_tunnel.save(None)?; + Ok(()) + } + + pub async fn rename_tunnel(&mut self, name: &str) -> Result<(), AnyError> { + is_valid_name(name)?; + + self.check_is_name_free(name).await?; + + let mut tunnel = match self.launcher_tunnel.load() { + Some(t) => t, + None => { + debug!(self.log, "No code server tunnel found, creating new one"); + let (persisted, _) = self.create_tunnel(name).await?; + self.launcher_tunnel.save(Some(persisted))?; + return Ok(()); + } + }; + + let locator = tunnel.locator(); + + let mut full_tunnel = spanf!( + self.log, + self.log.span("dev-tunnel.tag.get"), + self.client.get_tunnel(&locator, NO_REQUEST_OPTIONS) + ) + .map_err(|e| wrap(e, "failed to lookup tunnel"))?; + + full_tunnel.tags = vec![name.to_string(), VSCODE_CLI_TUNNEL_TAG.to_string()]; + spanf!( + self.log, + self.log.span("dev-tunnel.tag.update"), + self.client.update_tunnel(&full_tunnel, NO_REQUEST_OPTIONS) + ) + .map_err(|e| wrap(e, "failed to update tunnel tags"))?; + + tunnel.name = name.to_string(); + self.launcher_tunnel.save(Some(tunnel.clone()))?; + Ok(()) + } + + /// Starts a new tunnel for the code server on the port. Unlike `start_new_tunnel`, + /// this attempts to reuse or create a tunnel of a preferred name or of a generated friendly tunnel name. + pub async fn start_new_launcher_tunnel( + &mut self, + preferred_name: Option, + use_random_name: bool, + ) -> Result { + let (tunnel, persisted) = match self.launcher_tunnel.load() { + Some(mut persisted) => { + if let Some(name) = preferred_name { + if persisted.name.ne(&name) { + self.check_is_name_free(&name).await?; + let mut full_tunnel = spanf!( + self.log, + self.log.span("dev-tunnel.tag.get"), + self.client + .get_tunnel(&persisted.locator(), NO_REQUEST_OPTIONS) + ) + .map_err(|e| wrap(e, "failed to lookup tunnel"))?; + + info!(self.log, "Updating name of existing tunnel"); + + full_tunnel.tags = + vec![name.to_string(), VSCODE_CLI_TUNNEL_TAG.to_string()]; + if spanf!( + self.log, + self.log.span("dev-tunnel.tag.update"), + self.client.update_tunnel(&full_tunnel, NO_REQUEST_OPTIONS) + ) + .is_ok() + { + persisted.name = name.to_string(); + self.launcher_tunnel.save(Some(persisted.clone()))?; + } + } + } + + let tunnel_lookup = spanf!( + self.log, + self.log.span("dev-tunnel.tag.get"), + self.client.get_tunnel( + &persisted.locator(), + &TunnelRequestOptions { + include_ports: true, + token_scopes: vec!["host".to_string()], + ..Default::default() + } + ) + ); + + match tunnel_lookup { + Ok(ft) => (ft, persisted), + Err(HttpError::ResponseError(e)) + if e.status_code == StatusCode::NOT_FOUND + || e.status_code == StatusCode::FORBIDDEN => + { + let (persisted, tunnel) = self.create_tunnel(&persisted.name).await?; + self.launcher_tunnel.save(Some(persisted.clone()))?; + (tunnel, persisted) + } + Err(e) => return Err(AnyError::from(wrap(e, "failed to lookup tunnel"))), + } + } + None => { + debug!(self.log, "No code server tunnel found, creating new one"); + let name = self + .get_name_for_tunnel(preferred_name, use_random_name) + .await?; + let (persisted, full_tunnel) = self.create_tunnel(&name).await?; + self.launcher_tunnel.save(Some(persisted.clone()))?; + (full_tunnel, persisted) + } + }; + + let locator = TunnelLocator::try_from(&tunnel).unwrap(); + let host_token = get_host_token_from_tunnel(&tunnel); + + for port_to_delete in tunnel + .ports + .iter() + .filter(|p| p.port_number != CONTROL_PORT) + { + let output_fut = self.client.delete_tunnel_port( + &locator, + port_to_delete.port_number, + NO_REQUEST_OPTIONS, + ); + spanf!( + self.log, + self.log.span("dev-tunnel.port.delete"), + output_fut + ) + .map_err(|e| wrap(e, "failed to delete port"))?; + } + + // cleanup any old trailing tunnel endpoints + for endpoint in tunnel.endpoints { + let fut = self.client.delete_tunnel_endpoints( + &locator, + &endpoint.host_id, + None, + NO_REQUEST_OPTIONS, + ); + + spanf!(self.log, self.log.span("dev-tunnel.endpoint.prune"), fut) + .map_err(|e| wrap(e, "failed to prune tunnel endpoint"))?; + } + + self.start_tunnel( + locator.clone(), + &persisted, + self.client.clone(), + LookupAccessTokenProvider::new( + self.client.clone(), + locator, + self.log.clone(), + Some(host_token), + ), + ) + .await + } + + async fn create_tunnel(&mut self, name: &str) -> Result<(PersistedTunnel, Tunnel), AnyError> { + info!(self.log, "Creating tunnel with the name: {}", name); + + let mut tried_recycle = false; + + let new_tunnel = Tunnel { + tags: vec![name.to_string(), VSCODE_CLI_TUNNEL_TAG.to_string()], + ..Default::default() + }; + + loop { + let result = spanf!( + self.log, + self.log.span("dev-tunnel.create"), + self.client.create_tunnel(&new_tunnel, NO_REQUEST_OPTIONS) + ); + + match result { + Err(HttpError::ResponseError(e)) + if e.status_code == StatusCode::TOO_MANY_REQUESTS => + { + if !tried_recycle && self.try_recycle_tunnel().await? { + tried_recycle = true; + continue; + } + + return Err(AnyError::from(TunnelCreationFailed( + name.to_string(), + "You've exceeded the 10 machine limit for the port fowarding service. Please remove other machines before trying to add this machine.".to_string(), + ))); + } + Err(e) => { + return Err(AnyError::from(TunnelCreationFailed( + name.to_string(), + format!("{:?}", e), + ))) + } + Ok(t) => { + return Ok(( + PersistedTunnel { + cluster: t.cluster_id.clone().unwrap(), + id: t.tunnel_id.clone().unwrap(), + name: name.to_string(), + }, + t, + )) + } + } + } + } + + /// Tries to delete an unused tunnel, and then creates a tunnel with the + /// given `new_name`. + async fn try_recycle_tunnel(&mut self) -> Result { + trace!( + self.log, + "Tunnel limit hit, trying to recycle an old tunnel" + ); + + let existing_tunnels = self.list_all_server_tunnels().await?; + + let recyclable = existing_tunnels + .iter() + .filter(|t| { + t.status + .as_ref() + .and_then(|s| s.host_connection_count.as_ref()) + .map(|c| c.get_count()) + .unwrap_or(0) == 0 + }) + .choose(&mut rand::thread_rng()); + + match recyclable { + Some(tunnel) => { + trace!(self.log, "Recycling tunnel ID {:?}", tunnel.tunnel_id); + spanf!( + self.log, + self.log.span("dev-tunnel.delete"), + self.client + .delete_tunnel(&tunnel.try_into().unwrap(), NO_REQUEST_OPTIONS) + ) + .map_err(|e| wrap(e, "failed to execute `tunnel delete`"))?; + Ok(true) + } + None => { + trace!(self.log, "No tunnels available to recycle"); + Ok(false) + } + } + } + + async fn list_all_server_tunnels(&mut self) -> Result, AnyError> { + let tunnels = spanf!( + self.log, + self.log.span("dev-tunnel.listall"), + self.client.list_all_tunnels(&TunnelRequestOptions { + tags: vec![VSCODE_CLI_TUNNEL_TAG.to_string()], + require_all_tags: true, + ..Default::default() + }) + ) + .map_err(|e| wrap(e, "error listing current tunnels"))?; + + Ok(tunnels) + } + + async fn check_is_name_free(&mut self, name: &str) -> Result<(), AnyError> { + let existing = spanf!( + self.log, + self.log.span("dev-tunnel.rename.search"), + self.client.list_all_tunnels(&TunnelRequestOptions { + tags: vec![VSCODE_CLI_TUNNEL_TAG.to_string(), name.to_string()], + require_all_tags: true, + ..Default::default() + }) + ) + .map_err(|e| wrap(e, "failed to list existing tunnels"))?; + if !existing.is_empty() { + return Err(AnyError::from(TunnelCreationFailed( + name.to_string(), + "tunnel name already in use".to_string(), + ))); + }; + Ok(()) + } + + async fn get_name_for_tunnel( + &mut self, + preferred_name: Option, + mut use_random_name: bool, + ) -> Result { + let existing_tunnels = self.list_all_server_tunnels().await?; + let is_name_free = |n: &str| { + !existing_tunnels + .iter() + .any(|v| v.tags.iter().any(|t| t == n)) + }; + + if let Some(machine_name) = preferred_name { + let name = machine_name; + if let Err(e) = is_valid_name(&name) { + info!(self.log, "{} is an invalid name", e); + return Err(AnyError::from(wrap(e, "invalid name"))); + } + if is_name_free(&name) { + return Ok(name); + } + info!( + self.log, + "{} is already taken, using a random name instead", &name + ); + use_random_name = true; + } + + let mut placeholder_name = name_generator::generate_name(MAX_TUNNEL_NAME_LENGTH); + if use_random_name { + while !is_name_free(&placeholder_name) { + placeholder_name = name_generator::generate_name(MAX_TUNNEL_NAME_LENGTH); + } + return Ok(placeholder_name); + } + + loop { + let name = prompt_placeholder( + "What would you like to call this machine?", + &placeholder_name, + )?; + + if let Err(e) = is_valid_name(&name) { + info!(self.log, "{}", e); + continue; + } + + if is_name_free(&name) { + return Ok(name); + } + + info!(self.log, "The name {} is already in use", name); + } + } + + /// Hosts an existing tunnel, where the tunnel ID and host token are given. + pub async fn start_existing_tunnel( + &mut self, + tunnel: ExistingTunnel, + ) -> Result { + let tunnel_details = PersistedTunnel { + name: tunnel.tunnel_name, + id: tunnel.tunnel_id, + cluster: tunnel.cluster, + }; + + let mut mgmt = self.client.build(); + mgmt.authorization(tunnels::management::Authorization::Tunnel( + tunnel.host_token.clone(), + )); + + self.start_tunnel( + tunnel_details.locator(), + &tunnel_details, + mgmt.into(), + StaticAccessTokenProvider::new(tunnel.host_token), + ) + .await + } + + async fn start_tunnel( + &mut self, + locator: TunnelLocator, + tunnel_details: &PersistedTunnel, + client: TunnelManagementClient, + access_token: impl AccessTokenProvider + 'static, + ) -> Result { + let mut manager = ActiveTunnelManager::new(self.log.clone(), client, locator, access_token); + + let endpoint_result = spanf!( + self.log, + self.log.span("dev-tunnel.serve.callback"), + manager.get_endpoint() + ); + + let endpoint = match endpoint_result { + Ok(endpoint) => endpoint, + Err(e) => { + error!(self.log, "Error connecting to tunnel endpoint: {}", e); + manager.kill().await.ok(); + return Err(e); + } + }; + + debug!(self.log, "Connected to tunnel endpoint: {:?}", endpoint); + + Ok(ActiveTunnel { + name: tunnel_details.name.clone(), + manager, + }) + } +} + +struct ActiveTunnelManager { + close_tx: Option>, + endpoint_rx: watch::Receiver>>, + relay: Arc>, +} + +impl ActiveTunnelManager { + pub fn new( + log: log::Logger, + mgmt: TunnelManagementClient, + locator: TunnelLocator, + access_token: impl AccessTokenProvider + 'static, + ) -> ActiveTunnelManager { + let (endpoint_tx, endpoint_rx) = watch::channel(None); + let (close_tx, close_rx) = mpsc::channel(1); + + let relay = Arc::new(tokio::sync::Mutex::new(RelayTunnelHost::new(locator, mgmt))); + let relay_spawned = relay.clone(); + + tokio::spawn(async move { + ActiveTunnelManager::spawn_tunnel( + log, + relay_spawned, + close_rx, + endpoint_tx, + access_token, + ) + .await; + }); + + ActiveTunnelManager { + endpoint_rx, + relay, + close_tx: Some(close_tx), + } + } + + /// Adds a port for TCP/IP forwarding. + #[allow(dead_code)] // todo: port forwarding + pub async fn add_port_tcp(&self, port_number: u16) -> Result<(), WrappedError> { + self.relay + .lock() + .await + .add_port(&TunnelPort { + port_number, + protocol: Some(TUNNEL_PROTOCOL_AUTO.to_owned()), + ..Default::default() + }) + .await + .map_err(|e| wrap(e, "error adding port to relay"))?; + Ok(()) + } + + /// Adds a port for TCP/IP forwarding. + pub async fn add_port_direct( + &self, + port_number: u16, + ) -> Result, WrappedError> { + self.relay + .lock() + .await + .add_port_raw(&TunnelPort { + port_number, + protocol: Some(TUNNEL_PROTOCOL_AUTO.to_owned()), + ..Default::default() + }) + .await + .map_err(|e| wrap(e, "error adding port to relay")) + } + + /// Removes a port from TCP/IP forwarding. + pub async fn remove_port(&self, port_number: u16) -> Result<(), WrappedError> { + self.relay + .lock() + .await + .remove_port(port_number) + .await + .map_err(|e| wrap(e, "error remove port from relay")) + } + + /// Gets the most recent details from the tunnel process. Returns None if + /// the process exited before providing details. + pub async fn get_endpoint(&mut self) -> Result { + loop { + if let Some(details) = &*self.endpoint_rx.borrow() { + return details.clone().map_err(AnyError::from); + } + + if self.endpoint_rx.changed().await.is_err() { + return Err(DevTunnelError("tunnel creation cancelled".to_string()).into()); + } + } + } + + /// Kills the process, and waits for it to exit. + /// See https://tokio.rs/tokio/topics/shutdown#waiting-for-things-to-finish-shutting-down for how this works + pub async fn kill(&mut self) -> Result<(), AnyError> { + if let Some(tx) = self.close_tx.take() { + drop(tx); + } + + self.relay + .lock() + .await + .unregister() + .await + .map_err(|e| wrap(e, "error unregistering relay"))?; + + while self.endpoint_rx.changed().await.is_ok() {} + + Ok(()) + } + + async fn spawn_tunnel( + log: log::Logger, + relay: Arc>, + mut close_rx: mpsc::Receiver<()>, + endpoint_tx: watch::Sender>>, + access_token_provider: impl AccessTokenProvider + 'static, + ) { + let mut backoff = Backoff::new(Duration::from_secs(5), Duration::from_secs(120)); + + macro_rules! fail { + ($e: expr, $msg: expr) => { + warning!(log, "{}: {}", $msg, $e); + endpoint_tx.send(Some(Err($e))).ok(); + backoff.delay().await; + }; + } + + loop { + debug!(log, "Starting tunnel to server..."); + + let access_token = match access_token_provider.refresh_token().await { + Ok(t) => t, + Err(e) => { + fail!(e, "Error refreshing access token, will retry"); + continue; + } + }; + + // we don't bother making a client that can refresh the token, since + // the tunnel won't be able to host as soon as the access token expires. + let handle_res = { + let mut relay = relay.lock().await; + relay + .connect(&access_token) + .await + .map_err(|e| wrap(e, "error connecting to tunnel")) + }; + + let mut handle = match handle_res { + Ok(handle) => handle, + Err(e) => { + fail!(e, "Error connecting to relay, will retry"); + continue; + } + }; + + backoff.reset(); + endpoint_tx.send(Some(Ok(handle.endpoint().clone()))).ok(); + + tokio::select! { + // error is mapped like this prevent it being used across an await, + // which Rust dislikes since there's a non-sendable dyn Error in there + res = (&mut handle).map_err(|e| wrap(e, "error from tunnel connection")) => { + if let Err(e) = res { + fail!(e, "Tunnel exited unexpectedly, reconnecting"); + } else { + warning!(log, "Tunnel exited unexpectedly but gracefully, reconnecting"); + backoff.delay().await; + } + }, + _ = close_rx.recv() => { + trace!(log, "Tunnel closing gracefully"); + trace!(log, "Tunnel closed with result: {:?}", handle.close().await); + break; + } + } + } + } +} + +struct Backoff { + failures: u32, + base_duration: Duration, + max_duration: Duration, +} + +impl Backoff { + pub fn new(base_duration: Duration, max_duration: Duration) -> Self { + Self { + failures: 0, + base_duration, + max_duration, + } + } + + pub async fn delay(&mut self) { + tokio::time::sleep(self.next()).await + } + + pub fn next(&mut self) -> Duration { + self.failures += 1; + let duration = self + .base_duration + .checked_mul(self.failures) + .unwrap_or(self.max_duration); + std::cmp::min(duration, self.max_duration) + } + + pub fn reset(&mut self) { + self.failures = 0; + } +} diff --git a/cli/src/tunnels/legal.rs b/cli/src/tunnels/legal.rs new file mode 100644 index 00000000000..947fd07e4cd --- /dev/null +++ b/cli/src/tunnels/legal.rs @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use crate::state::{LauncherPaths, PersistedState}; +use crate::util::errors::{AnyError, MissingLegalConsent}; +use crate::util::input::prompt_yn; +use serde::{Deserialize, Serialize}; + +const LICENSE_TEXT: Option<&'static str> = option_env!("VSCODE_CLI_REMOTE_LICENSE_TEXT"); +const LICENSE_PROMPT: Option<&'static str> = option_env!("VSCODE_CLI_REMOTE_LICENSE_PROMPT"); + +#[derive(Clone, Default, Serialize, Deserialize)] +struct PersistedConsent { + pub consented: Option, +} + +pub fn require_consent( + paths: &LauncherPaths, + accept_server_license_terms: bool, +) -> Result<(), AnyError> { + match LICENSE_TEXT { + Some(t) => println!("{}", t.replace("\\n", "\r\n")), + None => return Ok(()), + } + + if accept_server_license_terms { + return Ok(()); + } + + let prompt = match LICENSE_PROMPT { + Some(p) => p, + None => return Ok(()), + }; + + let license: PersistedState = + PersistedState::new(paths.root().join("license_consent.json")); + + let mut save = false; + let mut load = license.load(); + + if !load.consented.unwrap_or(false) { + match prompt_yn(prompt) { + Ok(true) => { + save = true; + load.consented = Some(true); + } + Ok(false) => { + return Err(AnyError::from(MissingLegalConsent( + "Sorry you cannot use VS Code Server CLI without accepting the terms." + .to_string(), + ))) + } + Err(e) => return Err(AnyError::from(MissingLegalConsent(e.to_string()))), + } + } + + if save { + license.save(load)?; + } + + Ok(()) +} diff --git a/cli/src/tunnels/name_generator.rs b/cli/src/tunnels/name_generator.rs new file mode 100644 index 00000000000..f7c8cc92441 --- /dev/null +++ b/cli/src/tunnels/name_generator.rs @@ -0,0 +1,218 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use rand::prelude::*; + +// Adjectives in LEFT from Moby : +static LEFT: &[&str] = &[ + "admiring", + "adoring", + "affectionate", + "agitated", + "amazing", + "angry", + "awesome", + "beautiful", + "blissful", + "bold", + "boring", + "brave", + "busy", + "charming", + "clever", + "cool", + "compassionate", + "competent", + "condescending", + "confident", + "cranky", + "crazy", + "dazzling", + "determined", + "distracted", + "dreamy", + "eager", + "ecstatic", + "elastic", + "elated", + "elegant", + "eloquent", + "epic", + "exciting", + "fervent", + "festive", + "flamboyant", + "focused", + "friendly", + "frosty", + "funny", + "gallant", + "gifted", + "goofy", + "gracious", + "great", + "happy", + "hardcore", + "heuristic", + "hopeful", + "hungry", + "infallible", + "inspiring", + "interesting", + "intelligent", + "jolly", + "jovial", + "keen", + "kind", + "laughing", + "loving", + "lucid", + "magical", + "mystifying", + "modest", + "musing", + "naughty", + "nervous", + "nice", + "nifty", + "nostalgic", + "objective", + "optimistic", + "peaceful", + "pedantic", + "pensive", + "practical", + "priceless", + "quirky", + "quizzical", + "recursing", + "relaxed", + "reverent", + "romantic", + "sad", + "serene", + "sharp", + "silly", + "sleepy", + "stoic", + "strange", + "stupefied", + "suspicious", + "sweet", + "tender", + "thirsty", + "trusting", + "unruffled", + "upbeat", + "vibrant", + "vigilant", + "vigorous", + "wizardly", + "wonderful", + "xenodochial", + "youthful", + "zealous", + "zen", +]; + +static RIGHT: &[&str] = &[ + "albatross", + "antbird", + "antpitta", + "antshrike", + "antwren", + "babbler", + "barbet", + "blackbird", + "brushfinch", + "bulbul", + "bunting", + "cisticola", + "cormorant", + "crow", + "cuckoo", + "dove", + "drongo", + "duck", + "eagle", + "falcon", + "fantail", + "finch", + "flowerpecker", + "flycatcher", + "goose", + "goshawk", + "greenbul", + "grosbeak", + "gull", + "hawk", + "heron", + "honeyeater", + "hornbill", + "hummingbird", + "ibis", + "jay", + "kestrel", + "kingfisher", + "kite", + "lark", + "lorikeet", + "magpie", + "mockingbird", + "monarch", + "nightjar", + "oriole", + "owl", + "parakeet", + "parrot", + "partridge", + "penguin", + "petrel", + "pheasant", + "piculet", + "pigeon", + "pitta", + "prinia", + "puffin", + "quail", + "robin", + "sandpiper", + "seedeater", + "shearwater", + "sparrow", + "spinetail", + "starling", + "sunbird", + "swallow", + "swift", + "swiftlet", + "tanager", + "tapaculo", + "tern", + "thornbill", + "tinamou", + "trogon", + "tyrannulet", + "vireo", + "warbler", + "waxbill", + "weaver", + "whistler", + "woodpecker", + "wren", +]; + +/// Generates a random avian name, with the optional extra_random_length added +/// to reduce chance of in-flight collisions. +pub fn generate_name(max_length: usize) -> String { + let mut rng = rand::thread_rng(); + loop { + let left = LEFT[rng.gen_range(0..LEFT.len())]; + let right = RIGHT[rng.gen_range(0..RIGHT.len())]; + let s = format!("{}-{}", left, right); + if s.len() < max_length { + return s; + } + } +} diff --git a/cli/src/tunnels/paths.rs b/cli/src/tunnels/paths.rs new file mode 100644 index 00000000000..3c47b2575d7 --- /dev/null +++ b/cli/src/tunnels/paths.rs @@ -0,0 +1,216 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::{ + fs::{read_dir, read_to_string, remove_dir_all, write}, + path::PathBuf, +}; + +use serde::{Deserialize, Serialize}; + +use crate::{ + log, options, + state::{LauncherPaths, PersistedState}, + util::{ + errors::{wrap, AnyError, WrappedError}, + machine, + }, +}; + +const INSIDERS_INSTALL_FOLDER: &str = "server-insiders"; +const STABLE_INSTALL_FOLDER: &str = "server-stable"; +const EXPLORATION_INSTALL_FOLDER: &str = "server-exploration"; +const PIDFILE_SUFFIX: &str = ".pid"; +const LOGFILE_SUFFIX: &str = ".log"; + +pub struct ServerPaths { + // Directory into which the server is downloaded + pub server_dir: PathBuf, + // Executable path, within the server_id + pub executable: PathBuf, + // File where logs for the server should be written. + pub logfile: PathBuf, + // File where the process ID for the server should be written. + pub pidfile: PathBuf, +} + +impl ServerPaths { + // Queries the system to determine the process ID of the running server. + // Returns the process ID, if the server is running. + pub fn get_running_pid(&self) -> Option { + if let Some(pid) = self.read_pid() { + return match machine::process_at_path_exists(pid, &self.executable) { + true => Some(pid), + false => None, + }; + } + + if let Some(pid) = machine::find_running_process(&self.executable) { + // attempt to backfill process ID: + self.write_pid(pid).ok(); + return Some(pid); + } + + None + } + + /// Delete the server directory + pub fn delete(&self) -> Result<(), WrappedError> { + remove_dir_all(&self.server_dir).map_err(|e| { + wrap( + e, + format!("error deleting server dir {}", self.server_dir.display()), + ) + }) + } + + // VS Code Server pid + pub fn write_pid(&self, pid: u32) -> Result<(), WrappedError> { + write(&self.pidfile, &format!("{}", pid)).map_err(|e| { + wrap( + e, + format!("error writing process id into {}", self.pidfile.display()), + ) + }) + } + + fn read_pid(&self) -> Option { + read_to_string(&self.pidfile) + .ok() + .and_then(|s| s.parse::().ok()) + } +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct InstalledServer { + pub quality: options::Quality, + pub commit: String, + pub headless: bool, +} + +impl InstalledServer { + /// Gets path information about where a specific server should be stored. + pub fn server_paths(&self, p: &LauncherPaths) -> ServerPaths { + let base_folder = self.get_install_folder(p); + let server_dir = base_folder.join("bin").join(&self.commit); + ServerPaths { + executable: server_dir + .join("bin") + .join(self.quality.server_entrypoint()), + server_dir, + logfile: base_folder.join(format!(".{}{}", self.commit, LOGFILE_SUFFIX)), + pidfile: base_folder.join(format!(".{}{}", self.commit, PIDFILE_SUFFIX)), + } + } + + fn get_install_folder(&self, p: &LauncherPaths) -> PathBuf { + let name = match self.quality { + options::Quality::Insiders => INSIDERS_INSTALL_FOLDER, + options::Quality::Exploration => EXPLORATION_INSTALL_FOLDER, + options::Quality::Stable => STABLE_INSTALL_FOLDER, + }; + + p.root().join(if !self.headless { + format!("{}-web", name) + } else { + name.to_string() + }) + } +} + +pub struct LastUsedServers<'a> { + state: PersistedState>, + paths: &'a LauncherPaths, +} + +impl<'a> LastUsedServers<'a> { + pub fn new(paths: &'a LauncherPaths) -> LastUsedServers { + LastUsedServers { + state: PersistedState::new(paths.root().join("last-used-servers.json")), + paths, + } + } + + /// Adds a server as having been used most recently. Returns the number of retained server. + pub fn add(&self, server: InstalledServer) -> Result { + self.state.update_with(server, |server, l| { + if let Some(index) = l.iter().position(|s| s == &server) { + l.remove(index); + } + l.insert(0, server); + l.len() + }) + } + + /// Trims so that at most `max_servers` are saved on disk. + pub fn trim(&self, log: &log::Logger, max_servers: usize) -> Result<(), WrappedError> { + let mut servers = self.state.load(); + while servers.len() > max_servers { + let server = servers.pop().unwrap(); + debug!( + log, + "Removing old server {}/{}", + server.quality.get_machine_name(), + server.commit + ); + let server_paths = server.server_paths(self.paths); + server_paths.delete()?; + } + self.state.save(servers)?; + Ok(()) + } +} + +/// Prunes servers not currently running, and returns the deleted servers. +pub fn prune_stopped_servers(launcher_paths: &LauncherPaths) -> Result, AnyError> { + get_all_servers(launcher_paths) + .into_iter() + .map(|s| s.server_paths(launcher_paths)) + .filter(|s| s.get_running_pid().is_none()) + .map(|s| s.delete().map(|_| s)) + .collect::>() + .map_err(AnyError::from) +} + +// Gets a list of all servers which look like they might be running. +pub fn get_all_servers(lp: &LauncherPaths) -> Vec { + let mut servers: Vec = vec![]; + let mut server = InstalledServer { + commit: "".to_owned(), + headless: false, + quality: options::Quality::Stable, + }; + + add_server_paths_in_folder(lp, &server, &mut servers); + + server.headless = true; + add_server_paths_in_folder(lp, &server, &mut servers); + + server.headless = false; + server.quality = options::Quality::Insiders; + add_server_paths_in_folder(lp, &server, &mut servers); + + server.headless = true; + add_server_paths_in_folder(lp, &server, &mut servers); + + servers +} + +fn add_server_paths_in_folder( + lp: &LauncherPaths, + server: &InstalledServer, + servers: &mut Vec, +) { + let dir = server.get_install_folder(lp).join("bin"); + if let Ok(children) = read_dir(dir) { + for bin in children.flatten() { + servers.push(InstalledServer { + quality: server.quality, + headless: server.headless, + commit: bin.file_name().to_string_lossy().into(), + }); + } + } +} diff --git a/cli/src/tunnels/port_forwarder.rs b/cli/src/tunnels/port_forwarder.rs new file mode 100644 index 00000000000..9c79bebd22f --- /dev/null +++ b/cli/src/tunnels/port_forwarder.rs @@ -0,0 +1,130 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::collections::HashSet; + +use tokio::sync::{mpsc, oneshot}; + +use crate::{ + constants::CONTROL_PORT, + util::errors::{AnyError, CannotForwardControlPort, ServerHasClosed}, +}; + +use super::dev_tunnels::ActiveTunnel; + +pub enum PortForwardingRec { + Forward(u16, oneshot::Sender>), + Unforward(u16, oneshot::Sender>), +} + +/// Provides a port forwarding service for connected clients. Clients can make +/// requests on it, which are (and *must be*) processed by calling the `.process()` +/// method on the forwarder. +pub struct PortForwardingProcessor { + tx: mpsc::Sender, + rx: mpsc::Receiver, + forwarded: HashSet, +} + +impl PortForwardingProcessor { + pub fn new() -> Self { + let (tx, rx) = mpsc::channel(8); + Self { + tx, + rx, + forwarded: HashSet::new(), + } + } + + /// Gets a handle that can be passed off to consumers of port forwarding. + pub fn handle(&self) -> PortForwarding { + PortForwarding { + tx: self.tx.clone(), + } + } + + /// Receives port forwarding requests. Consumers MUST call `process()` + /// with the received requests. + pub async fn recv(&mut self) -> Option { + self.rx.recv().await + } + + /// Processes the incoming forwarding request. + pub async fn process(&mut self, req: PortForwardingRec, tunnel: &mut ActiveTunnel) { + match req { + PortForwardingRec::Forward(port, tx) => { + tx.send(self.process_forward(port, tunnel).await).ok(); + } + PortForwardingRec::Unforward(port, tx) => { + tx.send(self.process_unforward(port, tunnel).await).ok(); + } + } + } + + async fn process_unforward( + &mut self, + port: u16, + tunnel: &mut ActiveTunnel, + ) -> Result<(), AnyError> { + if port == CONTROL_PORT { + return Err(CannotForwardControlPort().into()); + } + + tunnel.remove_port(port).await?; + self.forwarded.remove(&port); + Ok(()) + } + + async fn process_forward( + &mut self, + port: u16, + tunnel: &mut ActiveTunnel, + ) -> Result { + if port == CONTROL_PORT { + return Err(CannotForwardControlPort().into()); + } + + if !self.forwarded.contains(&port) { + tunnel.add_port_tcp(port).await?; + self.forwarded.insert(port); + } + + tunnel.get_port_uri(port).await + } +} + +pub struct PortForwarding { + tx: mpsc::Sender, +} + +impl PortForwarding { + pub async fn forward(&self, port: u16) -> Result { + let (tx, rx) = oneshot::channel(); + let req = PortForwardingRec::Forward(port, tx); + + if self.tx.send(req).await.is_err() { + return Err(ServerHasClosed().into()); + } + + match rx.await { + Ok(r) => r, + Err(_) => Err(ServerHasClosed().into()), + } + } + + pub async fn unforward(&self, port: u16) -> Result<(), AnyError> { + let (tx, rx) = oneshot::channel(); + let req = PortForwardingRec::Unforward(port, tx); + + if self.tx.send(req).await.is_err() { + return Err(ServerHasClosed().into()); + } + + match rx.await { + Ok(r) => r, + Err(_) => Err(ServerHasClosed().into()), + } + } +} diff --git a/cli/src/tunnels/protocol.rs b/cli/src/tunnels/protocol.rs new file mode 100644 index 00000000000..e4751ffb45c --- /dev/null +++ b/cli/src/tunnels/protocol.rs @@ -0,0 +1,151 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use std::collections::HashMap; + +use crate::options::Quality; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Debug)] +#[serde(tag = "method", content = "params")] +#[allow(non_camel_case_types)] +pub enum ServerRequestMethod { + serve(ServeParams), + prune, + ping(EmptyResult), + forward(ForwardParams), + unforward(UnforwardParams), + gethostname(EmptyResult), + update(UpdateParams), + servermsg(ServerMessageParams), + callserverhttp(CallServerHttpParams), +} + +#[derive(Serialize, Debug)] +#[serde(tag = "method", content = "params", rename_all = "camelCase")] +#[allow(non_camel_case_types)] +pub enum ClientRequestMethod<'a> { + servermsg(RefServerMessageParams<'a>), + serverlog(ServerLog<'a>), + version(VersionParams), +} + +#[derive(Deserialize, Debug)] +pub struct ForwardParams { + pub port: u16, +} + +#[derive(Deserialize, Debug)] +pub struct UnforwardParams { + pub port: u16, +} + +#[derive(Serialize)] +pub struct ForwardResult { + pub uri: String, +} + +#[derive(Deserialize, Debug)] +pub struct ServeParams { + pub socket_id: u16, + pub commit_id: Option, + pub quality: Quality, + pub extensions: Vec, +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct EmptyResult {} + +#[derive(Serialize, Deserialize, Debug)] +pub struct UpdateParams { + pub do_update: bool, +} + +#[derive(Deserialize, Debug)] +pub struct ServerMessageParams { + pub i: u16, + #[serde(with = "serde_bytes")] + pub body: Vec, +} + +#[derive(Serialize, Debug)] +pub struct RefServerMessageParams<'a> { + pub i: u16, + #[serde(with = "serde_bytes")] + pub body: &'a [u8], +} + +#[derive(Serialize)] +pub struct UpdateResult { + pub up_to_date: bool, + pub did_update: bool, +} + +#[derive(Deserialize, Debug)] +pub struct ToServerRequest { + pub id: Option, + #[serde(flatten)] + pub params: ServerRequestMethod, +} + +#[derive(Serialize, Debug)] +pub struct ToClientRequest<'a> { + pub id: Option, + #[serde(flatten)] + pub params: ClientRequestMethod<'a>, +} + +#[derive(Serialize, Deserialize)] +pub struct SuccessResponse +where + T: Serialize, +{ + pub id: u8, + pub result: T, +} + +#[derive(Serialize, Deserialize)] +pub struct ErrorResponse { + pub id: u8, + pub error: ResponseError, +} + +#[derive(Serialize, Deserialize)] +pub struct ResponseError { + pub code: i32, + pub message: String, +} + +#[derive(Debug, Default, Serialize)] +pub struct ServerLog<'a> { + pub line: &'a str, + pub level: u8, +} + +#[derive(Serialize)] +pub struct GetHostnameResponse { + pub value: String, +} + +#[derive(Deserialize, Debug)] +pub struct CallServerHttpParams { + pub path: String, + pub method: String, + pub headers: HashMap, + pub body: Option>, +} + +#[derive(Serialize)] +pub struct CallServerHttpResult { + pub status: u16, + #[serde(with = "serde_bytes")] + pub body: Vec, + pub headers: HashMap, +} + +#[derive(Serialize, Debug)] +pub struct VersionParams { + pub version: &'static str, + pub protocol_version: u32, +} diff --git a/cli/src/tunnels/server_bridge_unix.rs b/cli/src/tunnels/server_bridge_unix.rs new file mode 100644 index 00000000000..f584ddfddc9 --- /dev/null +++ b/cli/src/tunnels/server_bridge_unix.rs @@ -0,0 +1,80 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use std::path::Path; + +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::{unix::OwnedWriteHalf, UnixStream}, + sync::mpsc::Sender, +}; + +use crate::util::errors::{wrap, AnyError}; + +pub struct ServerBridge { + write: OwnedWriteHalf, +} + +pub trait FromServerMessage { + fn from_server_message(index: u16, message: &[u8]) -> Self; + fn from_closed_server_bridge(i: u16) -> Self; +} + +pub async fn get_socket_rw_stream(path: &Path) -> Result { + let s = UnixStream::connect(path).await.map_err(|e| { + wrap( + e, + format!( + "error connecting to vscode server socket in {}", + path.display() + ), + ) + })?; + + Ok(s) +} + +const BUFFER_SIZE: usize = 65536; + +impl ServerBridge { + pub async fn new(path: &Path, index: u16, target: &Sender) -> Result + where + T: 'static + FromServerMessage + Send, + { + let stream = get_socket_rw_stream(path).await?; + let (mut read, write) = stream.into_split(); + + let tx = target.clone(); + tokio::spawn(async move { + let mut read_buf = vec![0; BUFFER_SIZE]; + loop { + match read.read(&mut read_buf).await { + Err(_) => return, + Ok(0) => { + let _ = tx.send(T::from_closed_server_bridge(index)).await; + return; // EOF + } + Ok(s) => { + let send = tx.send(T::from_server_message(index, &read_buf[..s])).await; + if send.is_err() { + return; + } + } + } + } + }); + + Ok(ServerBridge { write }) + } + + pub async fn write(&mut self, b: Vec) -> std::io::Result<()> { + self.write.write_all(&b).await?; + Ok(()) + } + + pub async fn close(mut self) -> std::io::Result<()> { + self.write.shutdown().await?; + Ok(()) + } +} diff --git a/cli/src/tunnels/server_bridge_windows.rs b/cli/src/tunnels/server_bridge_windows.rs new file mode 100644 index 00000000000..fb4b2b321f0 --- /dev/null +++ b/cli/src/tunnels/server_bridge_windows.rs @@ -0,0 +1,133 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::{path::Path, time::Duration}; + +use tokio::{ + io::{self, Interest}, + net::windows::named_pipe::{ClientOptions, NamedPipeClient}, + sync::mpsc, + time::sleep, +}; + +use crate::util::errors::{wrap, AnyError}; + +pub struct ServerBridge { + write_tx: mpsc::Sender>, +} + +pub trait FromServerMessage { + fn from_server_message(index: u16, message: &[u8]) -> Self; + fn from_closed_server_bridge(i: u16) -> Self; +} + +const BUFFER_SIZE: usize = 65536; + +pub async fn get_socket_rw_stream(path: &Path) -> Result { + // Tokio says we can need to try in a loop. Do so. + // https://docs.rs/tokio/latest/tokio/net/windows/named_pipe/struct.NamedPipeClient.html + let client = loop { + match ClientOptions::new().open(path) { + Ok(client) => break client, + // ERROR_PIPE_BUSY https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- + Err(e) if e.raw_os_error() == Some(231) => sleep(Duration::from_millis(100)).await, + Err(e) => { + return Err(AnyError::WrappedError(wrap( + e, + format!( + "error connecting to vscode server socket in {}", + path.display() + ), + ))) + } + } + }; + + Ok(client) +} + +impl ServerBridge { + pub async fn new(path: &Path, index: u16, target: &mpsc::Sender) -> Result + where + T: 'static + FromServerMessage + Send, + { + let client = get_socket_rw_stream(path).await?; + let (write_tx, mut write_rx) = mpsc::channel(4); + let read_tx = target.clone(); + tokio::spawn(async move { + let mut read_buf = vec![0; BUFFER_SIZE]; + let mut pending_recv: Option> = None; + + // See https://docs.rs/tokio/1.17.0/tokio/net/windows/named_pipe/struct.NamedPipeClient.html#method.ready + // With additional complications. If there's nothing queued to write, we wait for the + // pipe to be readable, or for something to come in. If there is something to + // write, wait until the pipe is either readable or writable. + loop { + let ready_result = if pending_recv.is_none() { + tokio::select! { + msg = write_rx.recv() => match msg { + Some(msg) => { + pending_recv = Some(msg); + client.ready(Interest::READABLE | Interest::WRITABLE).await + }, + None => return + }, + r = client.ready(Interest::READABLE) => r, + } + } else { + client.ready(Interest::READABLE | Interest::WRITABLE).await + }; + + let ready = match ready_result { + Ok(r) => r, + Err(_) => return, + }; + + if ready.is_readable() { + match client.try_read(&mut read_buf) { + Ok(0) => return, // EOF + Ok(s) => { + let send = read_tx + .send(T::from_server_message(index, &read_buf[..s])) + .await; + if send.is_err() { + return; + } + } + Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => { + continue; + } + Err(_) => return, + } + } + + if let Some(msg) = &pending_recv { + if ready.is_writable() { + match client.try_write(msg) { + Ok(n) if n == msg.len() => pending_recv = None, + Ok(n) => pending_recv = Some(msg[n..].to_vec()), + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + continue; + } + Err(_) => return, + } + } + } + } + }); + + Ok(ServerBridge { write_tx }) + } + + pub async fn write(&self, b: Vec) -> std::io::Result<()> { + self.write_tx.send(b).await.ok(); + Ok(()) + } + + pub async fn close(self) -> std::io::Result<()> { + drop(self.write_tx); + Ok(()) + } +} diff --git a/cli/src/tunnels/service.rs b/cli/src/tunnels/service.rs new file mode 100644 index 00000000000..8085f3b069a --- /dev/null +++ b/cli/src/tunnels/service.rs @@ -0,0 +1,82 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::path::PathBuf; + +use async_trait::async_trait; +use tokio::sync::mpsc; + +use crate::commands::tunnels::ShutdownSignal; +use crate::log; +use crate::state::LauncherPaths; +use crate::util::errors::AnyError; + +pub const SERVICE_LOG_FILE_NAME: &str = "tunnel-service.log"; + +#[async_trait] +pub trait ServiceContainer: Send { + async fn run_service( + &mut self, + log: log::Logger, + launcher_paths: LauncherPaths, + shutdown_rx: mpsc::Receiver, + ) -> Result<(), AnyError>; +} + +pub trait ServiceManager { + /// Registers the current executable as a service to run with the given set + /// of arguments. + fn register(&self, exe: PathBuf, args: &[&str]) -> Result<(), AnyError>; + + /// Runs the service using the given handle. The executable *must not* take + /// any action which may fail prior to calling this to ensure service + /// states may update. + fn run( + &self, + launcher_paths: LauncherPaths, + handle: impl 'static + ServiceContainer, + ) -> Result<(), AnyError>; + + /// Unregisters the current executable as a service. + fn unregister(&self) -> Result<(), AnyError>; +} + +#[cfg(target_os = "windows")] +pub type ServiceManagerImpl = super::service_windows::WindowsService; + +#[cfg(not(target_os = "windows"))] +pub type ServiceManagerImpl = UnimplementedServiceManager; + +#[allow(unreachable_code)] +pub fn create_service_manager(log: log::Logger) -> ServiceManagerImpl { + ServiceManagerImpl::new(log) +} + +pub struct UnimplementedServiceManager(); + +#[allow(dead_code)] +impl UnimplementedServiceManager { + fn new(_log: log::Logger) -> Self { + Self() + } +} + +impl ServiceManager for UnimplementedServiceManager { + fn register(&self, _exe: PathBuf, _args: &[&str]) -> Result<(), AnyError> { + unimplemented!("Service management is not supported on this platform"); + } + + fn run( + &self, + _launcher_paths: LauncherPaths, + _handle: impl 'static + ServiceContainer, + ) -> Result<(), AnyError> { + unimplemented!("Service management is not supported on this platform"); + } + + fn unregister(&self) -> Result<(), AnyError> { + unimplemented!("Service management is not supported on this platform"); + } +} diff --git a/cli/src/tunnels/service_windows.rs b/cli/src/tunnels/service_windows.rs new file mode 100644 index 00000000000..3d011dfa22b --- /dev/null +++ b/cli/src/tunnels/service_windows.rs @@ -0,0 +1,280 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use dialoguer::{theme::ColorfulTheme, Input, Password}; +use lazy_static::lazy_static; +use std::{ffi::OsString, sync::Mutex, thread, time::Duration}; +use tokio::sync::mpsc; +use windows_service::{ + define_windows_service, + service::{ + ServiceAccess, ServiceControl, ServiceControlAccept, ServiceErrorControl, ServiceExitCode, + ServiceInfo, ServiceStartType, ServiceState, ServiceStatus, ServiceType, + }, + service_control_handler::{self, ServiceControlHandlerResult}, + service_dispatcher, + service_manager::{ServiceManager, ServiceManagerAccess}, +}; + +use crate::{ + commands::tunnels::ShutdownSignal, + util::errors::{wrap, AnyError, WindowsNeedsElevation}, +}; +use crate::{ + log::{self, FileLogSink}, + state::LauncherPaths, +}; + +use super::service::{ + ServiceContainer, ServiceManager as CliServiceManager, SERVICE_LOG_FILE_NAME, +}; + +pub struct WindowsService { + log: log::Logger, +} + +const SERVICE_NAME: &str = "code_tunnel"; +const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS; + +impl WindowsService { + pub fn new(log: log::Logger) -> Self { + Self { log } + } +} + +impl CliServiceManager for WindowsService { + fn register(&self, exe: std::path::PathBuf, args: &[&str]) -> Result<(), AnyError> { + let service_manager = ServiceManager::local_computer( + None::<&str>, + ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE, + ) + .map_err(|e| WindowsNeedsElevation(format!("error getting service manager: {}", e)))?; + + let mut service_info = ServiceInfo { + name: OsString::from(SERVICE_NAME), + display_name: OsString::from("VS Code Tunnel"), + service_type: SERVICE_TYPE, + start_type: ServiceStartType::AutoStart, + error_control: ServiceErrorControl::Normal, + executable_path: exe, + launch_arguments: args.iter().map(OsString::from).collect(), + dependencies: vec![], + account_name: None, + account_password: None, + }; + + let existing_service = service_manager.open_service( + SERVICE_NAME, + ServiceAccess::QUERY_STATUS | ServiceAccess::START | ServiceAccess::CHANGE_CONFIG, + ); + let service = if let Ok(service) = existing_service { + service + .change_config(&service_info) + .map_err(|e| wrap(e, "error updating existing service"))?; + service + } else { + loop { + let (username, password) = prompt_credentials()?; + service_info.account_name = Some(format!(".\\{}", username).into()); + service_info.account_password = Some(password.into()); + + match service_manager.create_service( + &service_info, + ServiceAccess::CHANGE_CONFIG | ServiceAccess::START, + ) { + Ok(service) => break service, + Err(windows_service::Error::Winapi(e)) if Some(1057) == e.raw_os_error() => { + error!( + self.log, + "Invalid username or password, please try again..." + ); + } + Err(e) => return Err(wrap(e, "error registering service").into()), + } + } + }; + + service + .set_description("Service that runs `code tunnel` for access on vscode.dev") + .ok(); + + info!(self.log, "Successfully registered service..."); + + let status = service + .query_status() + .map(|s| s.current_state) + .unwrap_or(ServiceState::Stopped); + + if status == ServiceState::Stopped { + service + .start::<&str>(&[]) + .map_err(|e| wrap(e, "error starting service"))?; + } + + info!(self.log, "Tunnel service successfully started"); + Ok(()) + } + + #[allow(unused_must_use)] // triggers incorrectly on `define_windows_service!` + fn run( + &self, + launcher_paths: LauncherPaths, + handle: impl 'static + ServiceContainer, + ) -> Result<(), AnyError> { + let log = match FileLogSink::new( + log::Level::Debug, + &launcher_paths.root().join(SERVICE_LOG_FILE_NAME), + ) { + Ok(sink) => self.log.tee(sink), + Err(e) => { + warning!(self.log, "Failed to create service log file: {}", e); + self.log.clone() + } + }; + + // We put the handle into the global "impl" type and then take it out in + // my_service_main. This is needed just since we have to have that + // function at the root level, but need to pass in data later here... + SERVICE_IMPL.lock().unwrap().replace(ServiceImpl { + container: Box::new(handle), + launcher_paths, + log, + }); + + define_windows_service!(ffi_service_main, service_main); + + service_dispatcher::start(SERVICE_NAME, ffi_service_main) + .map_err(|e| wrap(e, "error starting service dispatcher").into()) + } + + fn unregister(&self) -> Result<(), AnyError> { + let service_manager = + ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT) + .map_err(|e| wrap(e, "error getting service manager"))?; + + let service = service_manager.open_service( + SERVICE_NAME, + ServiceAccess::QUERY_STATUS | ServiceAccess::STOP | ServiceAccess::DELETE, + ); + + let service = match service { + Ok(service) => service, + // Service does not exist: + Err(windows_service::Error::Winapi(e)) if Some(1060) == e.raw_os_error() => { + return Ok(()) + } + Err(e) => return Err(wrap(e, "error getting service handle").into()), + }; + + let service_status = service + .query_status() + .map_err(|e| wrap(e, "error getting service status"))?; + + if service_status.current_state != ServiceState::Stopped { + service + .stop() + .map_err(|e| wrap(e, "error getting stopping service"))?; + + while let Ok(ServiceState::Stopped) = service.query_status().map(|s| s.current_state) { + info!(self.log, "Polling for service to stop..."); + thread::sleep(Duration::from_secs(1)); + } + } + + service + .delete() + .map_err(|e| wrap(e, "error deleting service"))?; + + Ok(()) + } +} + +struct ServiceImpl { + container: Box, + launcher_paths: LauncherPaths, + log: log::Logger, +} + +lazy_static! { + static ref SERVICE_IMPL: Mutex> = Mutex::new(None); +} + +/// "main" function that the service calls in its own thread. +fn service_main(_arguments: Vec) -> Result<(), AnyError> { + let mut service = SERVICE_IMPL.lock().unwrap().take().unwrap(); + + // Create a channel to be able to poll a stop event from the service worker loop. + let (shutdown_tx, shutdown_rx) = mpsc::channel::(5); + let mut shutdown_tx = Some(shutdown_tx); + + // Define system service event handler that will be receiving service events. + let event_handler = move |control_event| -> ServiceControlHandlerResult { + match control_event { + ServiceControl::Interrogate => ServiceControlHandlerResult::NoError, + ServiceControl::Stop => { + shutdown_tx.take().and_then(|tx| tx.blocking_send(ShutdownSignal::ServiceStopped).ok()); + ServiceControlHandlerResult::NoError + } + _ => ServiceControlHandlerResult::NotImplemented, + } + }; + + let status_handle = service_control_handler::register(SERVICE_NAME, event_handler) + .map_err(|e| wrap(e, "error registering service event handler"))?; + + // Tell the system that service is running + status_handle + .set_service_status(ServiceStatus { + service_type: SERVICE_TYPE, + current_state: ServiceState::Running, + controls_accepted: ServiceControlAccept::STOP, + exit_code: ServiceExitCode::Win32(0), + checkpoint: 0, + wait_hint: Duration::default(), + process_id: None, + }) + .map_err(|e| wrap(e, "error marking service as running"))?; + + let result = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on( + service + .container + .run_service(service.log, service.launcher_paths, shutdown_rx), + ); + + status_handle + .set_service_status(ServiceStatus { + service_type: SERVICE_TYPE, + current_state: ServiceState::Stopped, + controls_accepted: ServiceControlAccept::empty(), + exit_code: ServiceExitCode::Win32(0), + checkpoint: 0, + wait_hint: Duration::default(), + process_id: None, + }) + .map_err(|e| wrap(e, "error marking service as stopped"))?; + + result +} + +fn prompt_credentials() -> Result<(String, String), AnyError> { + println!("Running a Windows service under your user requires your username and password."); + println!("These are sent to the Windows Service Manager and are not stored by VS Code."); + + let username: String = Input::with_theme(&ColorfulTheme::default()) + .with_prompt("Windows username:") + .interact_text() + .map_err(|e| wrap(e, "Failed to read username"))?; + + let password = Password::with_theme(&ColorfulTheme::default()) + .with_prompt("Windows password:") + .interact() + .map_err(|e| wrap(e, "Failed to read password"))?; + + Ok((username, password)) +} diff --git a/cli/src/update_service.rs b/cli/src/update_service.rs new file mode 100644 index 00000000000..3c1456ecc59 --- /dev/null +++ b/cli/src/update_service.rs @@ -0,0 +1,307 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::path::Path; + +use serde::Deserialize; + +use crate::{ + constants::VSCODE_CLI_UPDATE_ENDPOINT, + debug, log, options, spanf, + util::{ + errors::{ + AnyError, StatusError, UnsupportedPlatformError, UpdatesNotConfigured, WrappedError, + }, + io::ReportCopyProgress, + }, +}; + +/// Implementation of the VS Code Update service for use in the CLI. +pub struct UpdateService { + client: reqwest::Client, + log: log::Logger, +} + +/// Describes a specific release, can be created manually or returned from the update service. +pub struct Release { + pub name: String, + pub platform: Platform, + pub target: TargetKind, + pub quality: options::Quality, + pub commit: String, +} + +impl std::fmt::Display for Release { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} (commit {})", self.name, self.commit) + } +} + +#[derive(Deserialize)] +struct UpdateServerVersion { + pub version: String, + pub name: String, +} + +fn quality_download_segment(quality: options::Quality) -> &'static str { + match quality { + options::Quality::Stable => "stable", + options::Quality::Insiders => "insider", + options::Quality::Exploration => "exploration", + } +} + +impl UpdateService { + pub fn new(log: log::Logger, client: reqwest::Client) -> Self { + UpdateService { client, log } + } + + pub async fn get_release_by_semver_version( + &self, + platform: Platform, + target: TargetKind, + quality: options::Quality, + version: &str, + ) -> Result { + let update_endpoint = + VSCODE_CLI_UPDATE_ENDPOINT.ok_or_else(UpdatesNotConfigured::no_url)?; + let download_segment = target + .download_segment(platform) + .ok_or(UnsupportedPlatformError())?; + let download_url = format!( + "{}/api/versions/{}/{}/{}", + update_endpoint, + version, + download_segment, + quality_download_segment(quality), + ); + + let response = spanf!( + self.log, + self.log.span("server.version.resolve"), + self.client.get(download_url).send() + )?; + + if !response.status().is_success() { + return Err(StatusError::from_res(response).await?.into()); + } + + let res = response.json::().await?; + debug!(self.log, "Resolved version {} to {}", version, res.version); + + Ok(Release { + target, + platform, + quality, + name: res.name, + commit: res.version, + }) + } + + /// Gets the latest commit for the target of the given quality. + pub async fn get_latest_commit( + &self, + platform: Platform, + target: TargetKind, + quality: options::Quality, + ) -> Result { + let update_endpoint = + VSCODE_CLI_UPDATE_ENDPOINT.ok_or_else(UpdatesNotConfigured::no_url)?; + let download_segment = target + .download_segment(platform) + .ok_or(UnsupportedPlatformError())?; + let download_url = format!( + "{}/api/latest/{}/{}", + update_endpoint, + download_segment, + quality_download_segment(quality), + ); + + let response = spanf!( + self.log, + self.log.span("server.version.resolve"), + self.client.get(download_url).send() + )?; + + if !response.status().is_success() { + return Err(StatusError::from_res(response).await?.into()); + } + + let res = response.json::().await?; + debug!(self.log, "Resolved quality {} to {}", quality, res.version); + + Ok(Release { + target, + platform, + quality, + name: res.name, + commit: res.version, + }) + } + + /// Gets the download stream for the release. + pub async fn get_download_stream( + &self, + release: &Release, + ) -> Result { + let update_endpoint = + VSCODE_CLI_UPDATE_ENDPOINT.ok_or_else(UpdatesNotConfigured::no_url)?; + let download_segment = release + .target + .download_segment(release.platform) + .ok_or(UnsupportedPlatformError())?; + + let download_url = format!( + "{}/commit:{}/{}/{}", + update_endpoint, + release.commit, + download_segment, + quality_download_segment(release.quality), + ); + + let response = reqwest::get(&download_url).await?; + if !response.status().is_success() { + return Err(StatusError::from_res(response).await?.into()); + } + + Ok(response) + } +} + +pub fn unzip_downloaded_release( + compressed_file: &Path, + target_dir: &Path, + reporter: T, +) -> Result<(), WrappedError> +where + T: ReportCopyProgress, +{ + #[cfg(any(target_os = "windows", target_os = "macos"))] + { + use crate::util::zipper; + zipper::unzip_file(compressed_file, target_dir, reporter) + } + #[cfg(target_os = "linux")] + { + use crate::util::tar; + tar::decompress_tarball(compressed_file, target_dir, reporter) + } +} + +#[derive(Eq, PartialEq, Copy, Clone)] +pub enum TargetKind { + Server, + Archive, + Web, + Cli, +} + +impl TargetKind { + fn download_segment(&self, platform: Platform) -> Option { + match *self { + TargetKind::Server => Some(platform.headless()), + TargetKind::Archive => platform.archive(), + TargetKind::Web => Some(platform.web()), + TargetKind::Cli => Some(platform.cli()), + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum Platform { + LinuxAlpineX64, + LinuxAlpineARM64, + LinuxX64, + LinuxARM64, + LinuxARM32, + DarwinX64, + DarwinARM64, + WindowsX64, + WindowsX86, + WindowsARM64 +} + +impl Platform { + pub fn archive(&self) -> Option { + match self { + Platform::LinuxX64 => Some("linux-x64".to_owned()), + Platform::LinuxARM64 => Some("linux-arm64".to_owned()), + Platform::LinuxARM32 => Some("linux-armhf".to_owned()), + Platform::DarwinX64 => Some("darwin".to_owned()), + Platform::DarwinARM64 => Some("darwin-arm64".to_owned()), + Platform::WindowsX64 => Some("win32-x64-archive".to_owned()), + Platform::WindowsX86 => Some("win32-archive".to_owned()), + Platform::WindowsARM64 => Some("win32-arm64-archive".to_owned()), + _ => None, + } + } + pub fn headless(&self) -> String { + match self { + Platform::LinuxAlpineARM64 => "server-alpine-arm64", + Platform::LinuxAlpineX64 => "server-linux-alpine", + Platform::LinuxX64 => "server-linux-x64", + Platform::LinuxARM64 => "server-linux-arm64", + Platform::LinuxARM32 => "server-linux-armhf", + Platform::DarwinX64 => "server-darwin", + Platform::DarwinARM64 => "server-darwin-arm64", + Platform::WindowsX64 => "server-win32-x64", + Platform::WindowsX86 => "server-win32", + Platform::WindowsARM64 => "server-win32-arm64", + } + .to_owned() + } + + pub fn cli(&self) -> String { + match self { + Platform::LinuxAlpineARM64 => "cli-alpine-arm64", + Platform::LinuxAlpineX64 => "cli-alpine-x64", + Platform::LinuxX64 => "cli-linux-x64", + Platform::LinuxARM64 => "cli-linux-arm64", + Platform::LinuxARM32 => "cli-linux-armhf", + Platform::DarwinX64 => "cli-darwin-x64", + Platform::DarwinARM64 => "cli-darwin-arm64", + Platform::WindowsARM64 => "cli-win32-arm64", + Platform::WindowsX64 => "cli-win32-x64", + Platform::WindowsX86 => "cli-win32", + } + .to_owned() + } + + pub fn web(&self) -> String { + format!("{}-web", self.headless()) + } + + pub fn env_default() -> Option { + if cfg!(all( + target_os = "linux", + target_arch = "x86_64", + target_env = "musl" + )) { + Some(Platform::LinuxAlpineX64) + } else if cfg!(all( + target_os = "linux", + target_arch = "aarch64", + target_env = "musl" + )) { + Some(Platform::LinuxAlpineARM64) + } else if cfg!(all(target_os = "linux", target_arch = "x86_64")) { + Some(Platform::LinuxX64) + } else if cfg!(all(target_os = "linux", target_arch = "armhf")) { + Some(Platform::LinuxARM32) + } else if cfg!(all(target_os = "linux", target_arch = "aarch64")) { + Some(Platform::LinuxARM64) + } else if cfg!(all(target_os = "macos", target_arch = "x86_64")) { + Some(Platform::DarwinX64) + } else if cfg!(all(target_os = "macos", target_arch = "aarch64")) { + Some(Platform::DarwinARM64) + } else if cfg!(all(target_os = "windows", target_arch = "x86_64")) { + Some(Platform::WindowsX64) + } else if cfg!(all(target_os = "windows", target_arch = "x86")) { + Some(Platform::WindowsX86) + } else { + None + } + } +} diff --git a/cli/src/util.rs b/cli/src/util.rs new file mode 100644 index 00000000000..2ed47f2f263 --- /dev/null +++ b/cli/src/util.rs @@ -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. + *--------------------------------------------------------------------------------------------*/ + +mod is_integrated; + +pub mod command; +pub mod errors; +pub mod http; +pub mod input; +pub mod io; +pub mod machine; +pub mod prereqs; +pub mod sync; +pub use is_integrated::*; + +#[cfg(target_os = "linux")] +pub mod tar; + +#[cfg(any(target_os = "windows", target_os = "macos"))] +pub mod zipper; diff --git a/cli/src/util/command.rs b/cli/src/util/command.rs new file mode 100644 index 00000000000..7a7795e1590 --- /dev/null +++ b/cli/src/util/command.rs @@ -0,0 +1,77 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use super::errors::{wrap, WrappedError}; +use std::{ffi::OsStr, process::Stdio}; +use tokio::process::Command; + +pub async fn capture_command( + command_str: A, + args: I, +) -> Result +where + A: AsRef, + I: IntoIterator, + S: AsRef, +{ + Command::new(&command_str) + .args(args) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .output() + .await + .map_err(|e| { + wrap( + e, + format!( + "failed to execute command '{}'", + command_str.as_ref().to_string_lossy() + ), + ) + }) +} + +/// Kills and processes and all of its children. +#[cfg(target_os = "windows")] +pub async fn kill_tree(process_id: u32) -> Result<(), WrappedError> { + capture_command("taskkill", &["/t", "/pid", &process_id.to_string()]).await?; + Ok(()) +} + +/// Kills and processes and all of its children. +#[cfg(not(target_os = "windows"))] +pub async fn kill_tree(process_id: u32) -> Result<(), WrappedError> { + use futures::future::join_all; + use tokio::io::{AsyncBufReadExt, BufReader}; + + async fn kill_single_pid(process_id_str: String) { + capture_command("kill", &[&process_id_str]).await.ok(); + } + + // Rusty version of https://github.com/microsoft/vscode-js-debug/blob/main/src/targets/node/terminateProcess.sh + + let parent_id = process_id.to_string(); + let mut prgrep_cmd = Command::new("pgrep") + .arg("-P") + .arg(&parent_id) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .spawn() + .map_err(|e| wrap(e, "error enumerating process tree"))?; + + let mut kill_futures = vec![tokio::spawn( + async move { kill_single_pid(parent_id).await }, + )]; + + if let Some(stdout) = prgrep_cmd.stdout.take() { + let mut reader = BufReader::new(stdout).lines(); + while let Some(line) = reader.next_line().await.unwrap_or(None) { + kill_futures.push(tokio::spawn(async move { kill_single_pid(line).await })) + } + } + + join_all(kill_futures).await; + prgrep_cmd.kill().await.ok(); + Ok(()) +} diff --git a/cli/src/util/errors.rs b/cli/src/util/errors.rs new file mode 100644 index 00000000000..31fba617b5e --- /dev/null +++ b/cli/src/util/errors.rs @@ -0,0 +1,443 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use std::fmt::Display; + +use crate::constants::CONTROL_PORT; + +// Wraps another error with additional info. +#[derive(Debug, Clone)] +pub struct WrappedError { + message: String, + original: String, +} + +impl std::fmt::Display for WrappedError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}: {}", self.message, self.original) + } +} + +impl std::error::Error for WrappedError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +impl WrappedError { + // fn new(original: Box, message: String) -> WrappedError { + // WrappedError { message, original } + // } +} + +impl From for WrappedError { + fn from(e: reqwest::Error) -> WrappedError { + WrappedError { + message: format!( + "error requesting {}", + e.url().map_or("", |u| u.as_str()) + ), + original: format!("{}", e), + } + } +} + +pub fn wrap(original: T, message: S) -> WrappedError +where + T: Display, + S: Into, +{ + WrappedError { + message: message.into(), + original: format!("{}", original), + } +} + +// Error generated by an unsuccessful HTTP response +#[derive(Debug)] +pub struct StatusError { + url: String, + status_code: u16, + body: String, +} + +impl std::fmt::Display for StatusError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "error requesting {}: {} {}", + self.url, self.status_code, self.body + ) + } +} + +impl StatusError { + pub async fn from_res(res: reqwest::Response) -> Result { + let status_code = res.status().as_u16(); + let url = res.url().to_string(); + let body = res.text().await.map_err(|e| { + wrap( + e, + format!( + "failed to read response body on {} code from {}", + status_code, url + ), + ) + })?; + + Ok(StatusError { + url, + status_code, + body, + }) + } +} + +// When the user has not consented to the licensing terms in using the Launcher +#[derive(Debug)] +pub struct MissingLegalConsent(pub String); + +impl std::fmt::Display for MissingLegalConsent { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +// When the provided connection token doesn't match the one used to set up the original VS Code Server +// This is most likely due to a new user joining. +#[derive(Debug)] +pub struct MismatchConnectionToken(pub String); + +impl std::fmt::Display for MismatchConnectionToken { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +// When the VS Code server has an unrecognized extension (rather than zip or gz) +#[derive(Debug)] +pub struct InvalidServerExtensionError(pub String); + +impl std::fmt::Display for InvalidServerExtensionError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "invalid server extension '{}'", self.0) + } +} + +// When the tunnel fails to open +#[derive(Debug, Clone)] +pub struct DevTunnelError(pub String); + +impl std::fmt::Display for DevTunnelError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "could not open tunnel: {}", self.0) + } +} + +impl std::error::Error for DevTunnelError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +// When the server was downloaded, but the entrypoint scripts don't exist. +#[derive(Debug)] +pub struct MissingEntrypointError(); + +impl std::fmt::Display for MissingEntrypointError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Missing entrypoints in server download. Most likely this is a corrupted download. Please retry") + } +} + +#[derive(Debug)] +pub struct SetupError(pub String); + +impl std::fmt::Display for SetupError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "{}\r\n\r\nMore info at https://code.visualstudio.com/docs/remote/linux", + self.0 + ) + } +} + +#[derive(Debug)] +pub struct NoHomeForLauncherError(); + +impl std::fmt::Display for NoHomeForLauncherError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "No $HOME variable was found in your environment. Either set it, or specify a `--data-dir` manually when invoking the launcher.", + ) + } +} + +#[derive(Debug)] +pub struct InvalidTunnelName(pub String); + +impl std::fmt::Display for InvalidTunnelName { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", &self.0) + } +} + +#[derive(Debug)] +pub struct TunnelCreationFailed(pub String, pub String); + +impl std::fmt::Display for TunnelCreationFailed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "Could not create tunnel with name: {}\nReason: {}", + &self.0, &self.1 + ) + } +} + +#[derive(Debug)] +pub struct TunnelHostFailed(pub String); + +impl std::fmt::Display for TunnelHostFailed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", &self.0) + } +} + +#[derive(Debug)] +pub struct ExtensionInstallFailed(pub String); + +impl std::fmt::Display for ExtensionInstallFailed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Extension install failed: {}", &self.0) + } +} + +#[derive(Debug)] +pub struct MismatchedLaunchModeError(); + +impl std::fmt::Display for MismatchedLaunchModeError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "A server is already running, but it was not launched in the same listening mode (port vs. socket) as this request") + } +} + +#[derive(Debug)] +pub struct NoAttachedServerError(); + +impl std::fmt::Display for NoAttachedServerError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "No server is running") + } +} + +#[derive(Debug)] +pub struct ServerWriteError(); + +impl std::fmt::Display for ServerWriteError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Error writing to the server, it should be restarted") + } +} + +#[derive(Debug)] +pub struct RefreshTokenNotAvailableError(); + +impl std::fmt::Display for RefreshTokenNotAvailableError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Refresh token not available, authentication is required") + } +} + +#[derive(Debug)] +pub struct UnsupportedPlatformError(); + +impl std::fmt::Display for UnsupportedPlatformError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "This operation is not supported on your current platform" + ) + } +} + +#[derive(Debug)] +pub struct NoInstallInUserProvidedPath(pub String); + +impl std::fmt::Display for NoInstallInUserProvidedPath { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "No VS Code installation could be found in {}. You can run `code --use-quality=stable` to switch to the latest stable version of VS Code.", + self.0 + ) + } +} + +#[derive(Debug)] +pub struct InvalidRequestedVersion(); + +impl std::fmt::Display for InvalidRequestedVersion { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "The reqested version is invalid, expected one of 'stable', 'insiders', version number (x.y.z), or absolute path.", + ) + } +} + +#[derive(Debug)] +pub struct UserCancelledInstallation(); + +impl std::fmt::Display for UserCancelledInstallation { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Installation aborted.") + } +} + +#[derive(Debug)] +pub struct CannotForwardControlPort(); + +impl std::fmt::Display for CannotForwardControlPort { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Cannot forward or unforward port {}.", CONTROL_PORT) + } +} + +#[derive(Debug)] +pub struct ServerHasClosed(); + +impl std::fmt::Display for ServerHasClosed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Request cancelled because the server has closed") + } +} + +#[derive(Debug)] +pub struct UpdatesNotConfigured(pub String); + +impl UpdatesNotConfigured { + pub fn no_url() -> Self { + UpdatesNotConfigured("no service url".to_owned()) + } +} + +impl std::fmt::Display for UpdatesNotConfigured { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Update service is not configured: {}", self.0) + } +} +#[derive(Debug)] +pub struct ServiceAlreadyRegistered(); + +impl std::fmt::Display for ServiceAlreadyRegistered { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Already registered the service. Run `code tunnel service uninstall` to unregister it first") + } +} + +#[derive(Debug)] +pub struct WindowsNeedsElevation(pub String); + +impl std::fmt::Display for WindowsNeedsElevation { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!(f, "{}", self.0)?; + writeln!(f)?; + writeln!(f, "You may need to run this command as an administrator:")?; + writeln!(f, " 1. Open the start menu and search for Powershell")?; + writeln!(f, " 2. Right click and 'Run as administrator'")?; + if let Ok(exe) = std::env::current_exe() { + writeln!( + f, + " 3. Run &'{}' '{}'", + exe.display(), + std::env::args().skip(1).collect::>().join("' '") + ) + } else { + writeln!(f, " 3. Run the same command again",) + } + } +} + +#[derive(Debug)] +pub struct CorruptDownload(pub String); + +impl std::fmt::Display for CorruptDownload { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Error updating the VS Code CLI: {}", self.0) + } +} + +// Makes an "AnyError" enum that contains any of the given errors, in the form +// `enum AnyError { FooError(FooError) }` (when given `makeAnyError!(FooError)`). +// Useful to easily deal with application error types without making tons of "From" +// clauses. +macro_rules! makeAnyError { + ($($e:ident),*) => { + + #[derive(Debug)] + #[allow(clippy::enum_variant_names)] + pub enum AnyError { + $($e($e),)* + } + + impl std::fmt::Display for AnyError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match *self { + $(AnyError::$e(ref e) => e.fmt(f),)* + } + } + } + + impl std::error::Error for AnyError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } + } + + $(impl From<$e> for AnyError { + fn from(e: $e) -> AnyError { + AnyError::$e(e) + } + })* + }; +} + +makeAnyError!( + MissingLegalConsent, + MismatchConnectionToken, + DevTunnelError, + StatusError, + WrappedError, + InvalidServerExtensionError, + MissingEntrypointError, + SetupError, + NoHomeForLauncherError, + TunnelCreationFailed, + TunnelHostFailed, + InvalidTunnelName, + ExtensionInstallFailed, + MismatchedLaunchModeError, + NoAttachedServerError, + ServerWriteError, + UnsupportedPlatformError, + RefreshTokenNotAvailableError, + NoInstallInUserProvidedPath, + UserCancelledInstallation, + InvalidRequestedVersion, + CannotForwardControlPort, + ServerHasClosed, + ServiceAlreadyRegistered, + WindowsNeedsElevation, + UpdatesNotConfigured, + CorruptDownload +); + +impl From for AnyError { + fn from(e: reqwest::Error) -> AnyError { + AnyError::WrappedError(WrappedError::from(e)) + } +} diff --git a/cli/src/util/http.rs b/cli/src/util/http.rs new file mode 100644 index 00000000000..2dfd5cbe65a --- /dev/null +++ b/cli/src/util/http.rs @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use crate::util::errors::{self, WrappedError}; +use futures::stream::TryStreamExt; +use tokio::fs; +use tokio_util::compat::FuturesAsyncReadCompatExt; + +use super::io::{copy_async_progress, ReportCopyProgress}; + +pub async fn download_into_file( + filename: &std::path::Path, + progress: T, + res: reqwest::Response, +) -> Result +where + T: ReportCopyProgress, +{ + let mut file = fs::File::create(filename) + .await + .map_err(|e| errors::wrap(e, "failed to create file"))?; + + let content_length = res.content_length().unwrap_or(0); + let mut read = res + .bytes_stream() + .map_err(|e| futures::io::Error::new(futures::io::ErrorKind::Other, e)) + .into_async_read() + .compat(); + + copy_async_progress(progress, &mut read, &mut file, content_length) + .await + .map_err(|e| errors::wrap(e, "failed to download file"))?; + + Ok(file) +} diff --git a/cli/src/util/input.rs b/cli/src/util/input.rs new file mode 100644 index 00000000000..5f1acd7a266 --- /dev/null +++ b/cli/src/util/input.rs @@ -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. + *--------------------------------------------------------------------------------------------*/ +use crate::util::errors::wrap; +use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select}; +use indicatif::ProgressBar; +use std::fmt::Display; + +use super::{errors::WrappedError, io::ReportCopyProgress}; + +/// Wrapper around indicatif::ProgressBar that implements ReportCopyProgress. +pub struct ProgressBarReporter { + bar: ProgressBar, + has_set_total: bool, +} + +impl From for ProgressBarReporter { + fn from(bar: ProgressBar) -> Self { + ProgressBarReporter { + bar, + has_set_total: false, + } + } +} + +impl ReportCopyProgress for ProgressBarReporter { + fn report_progress(&mut self, bytes_so_far: u64, total_bytes: u64) { + if !self.has_set_total { + self.bar.set_length(total_bytes); + } + + if bytes_so_far == total_bytes { + self.bar.finish_and_clear(); + } else { + self.bar.set_position(bytes_so_far); + } + } +} + +pub fn prompt_yn(text: &str) -> Result { + Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt(text) + .default(true) + .interact() + .map_err(|e| wrap(e, "Failed to read confirm input")) +} + +pub fn prompt_options(text: &str, options: &[T]) -> Result +where + T: Display + Copy, +{ + let chosen = Select::with_theme(&ColorfulTheme::default()) + .with_prompt(text) + .items(options) + .default(0) + .interact() + .map_err(|e| wrap(e, "Failed to read select input"))?; + + Ok(options[chosen]) +} + +pub fn prompt_placeholder(question: &str, placeholder: &str) -> Result { + Input::with_theme(&ColorfulTheme::default()) + .with_prompt(question) + .default(placeholder.to_string()) + .interact_text() + .map_err(|e| wrap(e, "Failed to read confirm input")) +} diff --git a/cli/src/util/io.rs b/cli/src/util/io.rs new file mode 100644 index 00000000000..c55a9135e12 --- /dev/null +++ b/cli/src/util/io.rs @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use std::io; + +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; + +pub trait ReportCopyProgress { + fn report_progress(&mut self, bytes_so_far: u64, total_bytes: u64); +} + +/// Type that doesn't emit anything for download progress. +pub struct SilentCopyProgress(); + +impl ReportCopyProgress for SilentCopyProgress { + fn report_progress(&mut self, _bytes_so_far: u64, _total_bytes: u64) {} +} + +/// Copies from the reader to the writer, reporting progress to the provided +/// reporter every so often. +pub async fn copy_async_progress( + mut reporter: T, + reader: &mut R, + writer: &mut W, + total_bytes: u64, +) -> io::Result +where + R: AsyncRead + Unpin, + W: AsyncWrite + Unpin, + T: ReportCopyProgress, +{ + let mut buf = vec![0; 8 * 1024]; + let mut bytes_so_far = 0; + let mut bytes_last_reported = 0; + let report_granularity = std::cmp::min(total_bytes / 10, 2 * 1024 * 1024); + + reporter.report_progress(0, total_bytes); + + loop { + let read_buf = match reader.read(&mut buf).await { + Ok(0) => break, + Ok(n) => &buf[..n], + Err(e) => return Err(e), + }; + + writer.write_all(read_buf).await?; + + bytes_so_far += read_buf.len() as u64; + if bytes_so_far - bytes_last_reported > report_granularity { + bytes_last_reported = bytes_so_far; + reporter.report_progress(bytes_so_far, total_bytes); + } + } + + reporter.report_progress(bytes_so_far, total_bytes); + + Ok(bytes_so_far) +} diff --git a/cli/src/util/is_integrated.rs b/cli/src/util/is_integrated.rs new file mode 100644 index 00000000000..2bc87f47962 --- /dev/null +++ b/cli/src/util/is_integrated.rs @@ -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. + *--------------------------------------------------------------------------------------------*/ + +use std::{env, io}; + +/// Gets whether the current CLI seems like it's running in integrated mode, +/// by looking at the location of the exe and known VS Code files. +pub fn is_integrated_cli() -> io::Result { + let exe = env::current_exe()?; + + let parent = match exe.parent() { + Some(parent) if parent.file_name().and_then(|n| n.to_str()) == Some("bin") => parent, + _ => return Ok(false), + }; + + let parent = match parent.parent() { + Some(p) => p, + None => return Ok(false), + }; + + let expected_file = if cfg!(target_os = "macos") { + "node_modules.asar" + } else { + "resources.pak" + }; + + Ok(parent.join(expected_file).exists()) +} diff --git a/cli/src/util/machine.rs b/cli/src/util/machine.rs new file mode 100644 index 00000000000..cac5407893a --- /dev/null +++ b/cli/src/util/machine.rs @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::path::Path; +use sysinfo::{Pid, PidExt, ProcessExt, System, SystemExt}; + +pub fn process_at_path_exists(pid: u32, name: &Path) -> bool { + // TODO https://docs.rs/sysinfo/latest/sysinfo/index.html#usage + let mut sys = System::new_all(); + sys.refresh_processes(); + + let name_str = format!("{}", name.display()); + match sys.process(Pid::from_u32(pid)) { + Some(process) => { + for cmd in process.cmd() { + if cmd.contains(&name_str) { + return true; + } + } + } + None => { + return false; + } + } + + false +} +pub fn process_exists(pid: u32) -> bool { + let mut sys = System::new_all(); + sys.refresh_processes(); + sys.process(Pid::from_u32(pid)).is_some() +} + +pub fn find_running_process(name: &Path) -> Option { + // TODO https://docs.rs/sysinfo/latest/sysinfo/index.html#usage + let mut sys = System::new_all(); + sys.refresh_processes(); + + let name_str = format!("{}", name.display()); + + for (pid, process) in sys.processes() { + for cmd in process.cmd() { + if cmd.contains(&name_str) { + return Some(pid.as_u32()); + } + } + } + None +} diff --git a/cli/src/util/prereqs.rs b/cli/src/util/prereqs.rs new file mode 100644 index 00000000000..86d5020efa1 --- /dev/null +++ b/cli/src/util/prereqs.rs @@ -0,0 +1,301 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use std::cmp::Ordering; + +use super::command::capture_command; +use crate::update_service::Platform; +use crate::util::errors::SetupError; +use lazy_static::lazy_static; +use regex::bytes::Regex as BinRegex; +use regex::Regex; +use tokio::fs; + +use super::errors::AnyError; + +lazy_static! { + static ref LDCONFIG_STDC_RE: Regex = Regex::new(r"libstdc\+\+.* => (.+)").unwrap(); + static ref LDD_VERSION_RE: BinRegex = BinRegex::new(r"^ldd.*(.+)\.(.+)\s").unwrap(); + static ref LIBSTD_CXX_VERSION_RE: BinRegex = + BinRegex::new(r"GLIBCXX_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?").unwrap(); + static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 18); + static ref MIN_LDD_VERSION: SimpleSemver = SimpleSemver::new(2, 17, 0); +} + +pub struct PreReqChecker {} + +impl Default for PreReqChecker { + fn default() -> Self { + Self::new() + } +} + +impl PreReqChecker { + pub fn new() -> PreReqChecker { + PreReqChecker {} + } + + #[cfg(not(target_os = "linux"))] + pub async fn verify(&self) -> Result { + Platform::env_default().ok_or_else(|| { + SetupError("VS Code it not supported on this platform".to_owned()).into() + }) + } + + #[cfg(target_os = "linux")] + pub async fn verify(&self) -> Result { + let (gnu_a, gnu_b, or_musl) = tokio::join!( + check_glibc_version(), + check_glibcxx_version(), + check_musl_interpreter() + ); + + if gnu_a.is_ok() && gnu_b.is_ok() { + return Ok(if cfg!(target_arch = "x86_64") { + Platform::LinuxX64 + } else if cfg!(target_arch = "armhf") { + Platform::LinuxARM32 + } else { + Platform::LinuxARM64 + }); + } + + if or_musl.is_ok() { + return Ok(if cfg!(target_arch = "x86_64") { + Platform::LinuxAlpineX64 + } else { + Platform::LinuxAlpineARM64 + }); + } + + let mut errors: Vec = vec![]; + if let Err(e) = gnu_a { + errors.push(e); + } else if let Err(e) = gnu_b { + errors.push(e); + } + + if let Err(e) = or_musl { + errors.push(e); + } + + let bullets = errors + .iter() + .map(|e| format!(" - {}", e)) + .collect::>() + .join("\n"); + + Err(AnyError::from(SetupError(format!( + "This machine not meet VS Code Server's prerequisites, expected either...\n{}", + bullets, + )))) + } +} + +#[allow(dead_code)] +async fn check_musl_interpreter() -> Result<(), String> { + const MUSL_PATH: &str = if cfg!(target_platform = "aarch64") { + "/lib/ld-musl-aarch64.so.1" + } else { + "/lib/ld-musl-x86_64.so.1" + }; + + if fs::metadata(MUSL_PATH).await.is_err() { + return Err(format!( + "find {}, which is required to run the VS Code Server in musl environments", + MUSL_PATH + )); + } + + Ok(()) +} + +#[allow(dead_code)] +async fn check_glibc_version() -> Result<(), String> { + let ldd_version = capture_command("ldd", ["--version"]) + .await + .ok() + .and_then(|o| extract_ldd_version(&o.stdout)); + + if let Some(v) = ldd_version { + return if v.gte(&MIN_LDD_VERSION) { + Ok(()) + } else { + Err(format!( + "find GLIBC >= 2.17 (but found {} instead) for GNU environments", + v + )) + }; + } + + Ok(()) +} + +#[allow(dead_code)] +async fn check_glibcxx_version() -> Result<(), String> { + let mut libstdc_path: Option = None; + + const DEFAULT_LIB_PATH: &str = "/usr/lib64/libstdc++.so.6"; + const LDCONFIG_PATH: &str = "/sbin/ldconfig"; + + if fs::metadata(DEFAULT_LIB_PATH).await.is_ok() { + libstdc_path = Some(DEFAULT_LIB_PATH.to_owned()); + } else if fs::metadata(LDCONFIG_PATH).await.is_ok() { + libstdc_path = capture_command(LDCONFIG_PATH, ["-p"]) + .await + .ok() + .and_then(|o| extract_libstd_from_ldconfig(&o.stdout)); + } + + match libstdc_path { + Some(path) => match fs::read(&path).await { + Ok(contents) => check_for_sufficient_glibcxx_versions(contents), + Err(e) => Err(format!( + "validate GLIBCXX version for GNU environments, but could not: {}", + e + )), + }, + None => Err("find libstdc++.so or ldconfig for GNU environments".to_owned()), + } +} + +#[allow(dead_code)] +fn check_for_sufficient_glibcxx_versions(contents: Vec) -> Result<(), String> { + let all_versions: Vec = LIBSTD_CXX_VERSION_RE + .captures_iter(&contents) + .map(|m| SimpleSemver { + major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())), + minor: m.get(2).map_or(0, |s| u32_from_bytes(s.as_bytes())), + patch: m.get(3).map_or(0, |s| u32_from_bytes(s.as_bytes())), + }) + .collect(); + + if !all_versions.iter().any(|v| MIN_CXX_VERSION.gte(v)) { + return Err(format!( + "find GLIBCXX >= 3.4.18 (but found {} instead) for GNU environments", + all_versions + .iter() + .map(String::from) + .collect::>() + .join(", ") + )); + } + + Ok(()) +} + +fn extract_ldd_version(output: &[u8]) -> Option { + LDD_VERSION_RE.captures(output).map(|m| SimpleSemver { + major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())), + minor: m.get(2).map_or(0, |s| u32_from_bytes(s.as_bytes())), + patch: 0, + }) +} + +fn extract_libstd_from_ldconfig(output: &[u8]) -> Option { + String::from_utf8_lossy(output) + .lines() + .find_map(|l| LDCONFIG_STDC_RE.captures(l)) + .and_then(|cap| cap.get(1)) + .map(|cap| cap.as_str().to_owned()) +} + +fn u32_from_bytes(b: &[u8]) -> u32 { + String::from_utf8_lossy(b).parse::().unwrap_or(0) +} + +#[derive(Debug, PartialEq)] +struct SimpleSemver { + major: u32, + minor: u32, + patch: u32, +} + +impl From<&SimpleSemver> for String { + fn from(s: &SimpleSemver) -> Self { + format!("v{}.{}.{}", s.major, s.minor, s.patch) + } +} + +impl std::fmt::Display for SimpleSemver { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", String::from(self)) + } +} + +#[allow(dead_code)] +impl SimpleSemver { + fn new(major: u32, minor: u32, patch: u32) -> SimpleSemver { + SimpleSemver { + major, + minor, + patch, + } + } + + fn gte(&self, other: &SimpleSemver) -> bool { + match self.major.cmp(&other.major) { + Ordering::Greater => true, + Ordering::Less => false, + Ordering::Equal => match self.minor.cmp(&other.minor) { + Ordering::Greater => true, + Ordering::Less => false, + Ordering::Equal => self.patch >= other.patch, + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_extract_libstd_from_ldconfig() { + let actual = " + libstoken.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstoken.so.1 + libstemmer.so.0d (libc6,x86-64) => /lib/x86_64-linux-gnu/libstemmer.so.0d + libstdc++.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstdc++.so.6 + libstartup-notification-1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstartup-notification-1.so.0 + libssl3.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl3.so + ".to_owned().into_bytes(); + + assert_eq!( + extract_libstd_from_ldconfig(&actual), + Some("/lib/x86_64-linux-gnu/libstdc++.so.6".to_owned()), + ); + + assert_eq!( + extract_libstd_from_ldconfig(&"nothing here!".to_owned().into_bytes()), + None, + ); + } + + #[test] + fn test_gte() { + assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 2, 3))); + assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(0, 10, 10))); + assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 1, 10))); + + assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 2, 10))); + assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 3, 1))); + assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(2, 2, 1))); + } + + #[test] + fn check_for_sufficient_glibcxx_versions() { + let actual = "ldd (Ubuntu GLIBC 2.31-0ubuntu9.7) 2.31 + Copyright (C) 2020 Free Software Foundation, Inc. + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + Written by Roland McGrath and Ulrich Drepper." + .to_owned() + .into_bytes(); + + assert_eq!( + extract_ldd_version(&actual), + Some(SimpleSemver::new(2, 31, 0)), + ); + } +} diff --git a/cli/src/util/sync.rs b/cli/src/util/sync.rs new file mode 100644 index 00000000000..5f33419488a --- /dev/null +++ b/cli/src/util/sync.rs @@ -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. + *--------------------------------------------------------------------------------------------*/ +use tokio::sync::watch::{ + self, + error::{RecvError, SendError}, +}; + +#[derive(Clone)] +pub struct Barrier(watch::Receiver>) +where + T: Copy; + +impl Barrier +where + T: Copy, +{ + /// Waits for the barrier to be closed, returning a value if one was sent. + pub async fn wait(&mut self) -> Result { + loop { + self.0.changed().await?; + + if let Some(v) = *(self.0.borrow()) { + return Ok(v); + } + } + } +} + +pub struct BarrierOpener(watch::Sender>); + +impl BarrierOpener { + /// Closes the barrier. + pub fn open(self, value: T) -> Result<(), SendError>> { + self.0.send(Some(value)) + } +} + +/// The Barrier is something that can be opened once from one side, +/// and is thereafter permanently closed. It can contain a value. +pub fn new_barrier() -> (Barrier, BarrierOpener) +where + T: Copy, +{ + let (closed_tx, closed_rx) = watch::channel(None); + (Barrier(closed_rx), BarrierOpener(closed_tx)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_barrier_close_after_spawn() { + let (mut barrier, opener) = new_barrier::(); + let (tx, rx) = tokio::sync::oneshot::channel::(); + + tokio::spawn(async move { + tx.send(barrier.wait().await.unwrap()).unwrap(); + }); + + opener.open(42).unwrap(); + + assert!(rx.await.unwrap() == 42); + } + + #[tokio::test] + async fn test_barrier_close_before_spawn() { + let (barrier, opener) = new_barrier::(); + let (tx1, rx1) = tokio::sync::oneshot::channel::(); + let (tx2, rx2) = tokio::sync::oneshot::channel::(); + + opener.open(42).unwrap(); + let mut b1 = barrier.clone(); + tokio::spawn(async move { + tx1.send(b1.wait().await.unwrap()).unwrap(); + }); + let mut b2 = barrier.clone(); + tokio::spawn(async move { + tx2.send(b2.wait().await.unwrap()).unwrap(); + }); + + assert!(rx1.await.unwrap() == 42); + assert!(rx2.await.unwrap() == 42); + } +} diff --git a/cli/src/util/tar.rs b/cli/src/util/tar.rs new file mode 100644 index 00000000000..b5884e67afd --- /dev/null +++ b/cli/src/util/tar.rs @@ -0,0 +1,105 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use crate::util::errors::{wrap, WrappedError}; + +use flate2::read::GzDecoder; +use std::fs; +use std::io::{Seek, SeekFrom}; +use std::path::{Path, PathBuf}; +use tar::Archive; + +use super::io::ReportCopyProgress; + +fn should_skip_first_segment(file: &fs::File) -> Result { + // unfortunately, we need to re-read the archive here since you cannot reuse + // `.entries()`. But this will generally only look at one or two files, so this + // should be acceptably speedy... If not, we could hardcode behavior for + // different types of archives. + + let tar = GzDecoder::new(file); + let mut archive = Archive::new(tar); + let mut entries = archive + .entries() + .map_err(|e| wrap(e, "error opening archive"))?; + + let first_name = { + let file = entries + .next() + .expect("expected not to have an empty archive") + .map_err(|e| wrap(e, "error reading entry file"))?; + + let path = file.path().expect("expected to have path"); + + path.iter() + .next() + .expect("expected to have non-empty name") + .to_owned() + }; + + let mut had_multiple = false; + for file in entries.flatten() { + had_multiple = true; + if let Ok(name) = file.path() { + if name.iter().next() != Some(&first_name) { + return Ok(false); + } + } + } + + Ok(had_multiple) // prefix removal is invalid if there's only a single file +} + +pub fn decompress_tarball( + path: &Path, + parent_path: &Path, + mut reporter: T, +) -> Result<(), WrappedError> +where + T: ReportCopyProgress, +{ + let mut tar_gz = fs::File::open(path) + .map_err(|e| wrap(e, format!("error opening file {}", path.display())))?; + let skip_first = should_skip_first_segment(&tar_gz)?; + + // reset since skip logic read the tar already: + tar_gz + .seek(SeekFrom::Start(0)) + .map_err(|e| wrap(e, "error resetting seek position"))?; + + let tar = GzDecoder::new(tar_gz); + let mut archive = Archive::new(tar); + + let results = archive + .entries() + .map_err(|e| wrap(e, format!("error opening archive {}", path.display())))? + .filter_map(|e| e.ok()) + .map(|mut entry| { + let entry_path = entry + .path() + .map_err(|e| wrap(e, "error reading entry path"))?; + + let path = parent_path.join(if skip_first { + entry_path.iter().skip(1).collect::() + } else { + entry_path.into_owned() + }); + + if let Some(p) = path.parent() { + fs::create_dir_all(&p) + .map_err(|e| wrap(e, format!("could not create dir for {}", p.display())))?; + } + + entry + .unpack(&path) + .map_err(|e| wrap(e, format!("error unpacking {}", path.display())))?; + Ok(path) + }) + .collect::, WrappedError>>()?; + + // Tarballs don't have a way to get the number of entries ahead of time + reporter.report_progress(results.len() as u64, results.len() as u64); + + Ok(()) +} diff --git a/cli/src/util/zipper.rs b/cli/src/util/zipper.rs new file mode 100644 index 00000000000..bfb7f4085b6 --- /dev/null +++ b/cli/src/util/zipper.rs @@ -0,0 +1,155 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +use super::errors::{wrap, WrappedError}; +use super::io::ReportCopyProgress; +use std::fs::{self, File}; +use std::io; +use std::path::Path; +use std::path::PathBuf; +use zip::read::ZipFile; +use zip::{self, ZipArchive}; + +// Borrowed and modified from https://github.com/zip-rs/zip/blob/master/examples/extract.rs + +/// Returns whether all files in the archive start with the same path segment. +/// If so, it's an indication we should skip that segment when extracting. +fn should_skip_first_segment(archive: &mut ZipArchive) -> bool { + let first_name = { + let file = archive + .by_index_raw(0) + .expect("expected not to have an empty archive"); + + let path = file + .enclosed_name() + .expect("expected to have path") + .iter() + .next() + .expect("expected to have non-empty name"); + + path.to_owned() + }; + + for i in 1..archive.len() { + if let Ok(file) = archive.by_index_raw(i) { + if let Some(name) = file.enclosed_name() { + if name.iter().next() != Some(&first_name) { + return false; + } + } + } + } + + archive.len() > 1 // prefix removal is invalid if there's only a single file +} + +pub fn unzip_file(path: &Path, parent_path: &Path, mut reporter: T) -> Result<(), WrappedError> +where + T: ReportCopyProgress, +{ + let file = fs::File::open(path) + .map_err(|e| wrap(e, format!("unable to open file {}", path.display())))?; + + let mut archive = zip::ZipArchive::new(file) + .map_err(|e| wrap(e, format!("failed to open zip archive {}", path.display())))?; + + let skip_segments_no = if should_skip_first_segment(&mut archive) { + 1 + } else { + 0 + }; + + for i in 0..archive.len() { + reporter.report_progress(i as u64, archive.len() as u64); + let mut file = archive + .by_index(i) + .map_err(|e| wrap(e, format!("could not open zip entry {}", i)))?; + + let outpath: PathBuf = match file.enclosed_name() { + Some(path) => { + let mut full_path = PathBuf::from(parent_path); + full_path.push(PathBuf::from_iter(path.iter().skip(skip_segments_no))); + full_path + } + None => continue, + }; + + if file.is_dir() || file.name().ends_with('/') { + fs::create_dir_all(&outpath) + .map_err(|e| wrap(e, format!("could not create dir for {}", outpath.display())))?; + apply_permissions(&file, &outpath)?; + continue; + } + + if let Some(p) = outpath.parent() { + fs::create_dir_all(&p) + .map_err(|e| wrap(e, format!("could not create dir for {}", outpath.display())))?; + } + + #[cfg(unix)] + { + use libc::S_IFLNK; + use std::io::Read; + use std::os::unix::ffi::OsStringExt; + + if matches!(file.unix_mode(), Some(mode) if mode & (S_IFLNK as u32) == (S_IFLNK as u32)) + { + let mut link_to = Vec::new(); + file.read_to_end(&mut link_to).map_err(|e| { + wrap( + e, + format!("could not read symlink linkpath {}", outpath.display()), + ) + })?; + + let link_path = PathBuf::from(std::ffi::OsString::from_vec(link_to)); + std::os::unix::fs::symlink(link_path, &outpath).map_err(|e| { + wrap(e, format!("could not create symlink {}", outpath.display())) + })?; + continue; + } + } + + let mut outfile = fs::File::create(&outpath).map_err(|e| { + wrap( + e, + format!( + "unable to open file to write {} (from {:?})", + outpath.display(), + file.enclosed_name().map(|p| p.to_string_lossy()), + ), + ) + })?; + + io::copy(&mut file, &mut outfile) + .map_err(|e| wrap(e, format!("error copying file {}", outpath.display())))?; + + apply_permissions(&file, &outpath)?; + } + + reporter.report_progress(archive.len() as u64, archive.len() as u64); + + Ok(()) +} + +#[cfg(unix)] +fn apply_permissions(file: &ZipFile, outpath: &Path) -> Result<(), WrappedError> { + use std::os::unix::fs::PermissionsExt; + + if let Some(mode) = file.unix_mode() { + fs::set_permissions(&outpath, fs::Permissions::from_mode(mode)).map_err(|e| { + wrap( + e, + format!("error setting permissions on {}", outpath.display()), + ) + })?; + } + + Ok(()) +} + +#[cfg(windows)] +fn apply_permissions(_file: &ZipFile, _outpath: &Path) -> Result<(), WrappedError> { + Ok(()) +} diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index f2ebd926da2..37a5a9137bb 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.2.0" }, "capabilities": { "virtualWorkspaces": true, @@ -52,7 +52,8 @@ ".devcontainer.json" ], "filenamePatterns": [ - "**/User/snippets/*.json" + "**/User/snippets/*.json", + "**/User/profiles/*/snippets/*.json" ] }, { "id": "json", @@ -70,6 +71,10 @@ "fileMatch": "%APP_SETTINGS_HOME%/keybindings.json", "url": "vscode://schemas/keybindings" }, + { + "fileMatch": "%APP_SETTINGS_HOME%/profiles/*/keybindings.json", + "url": "vscode://schemas/keybindings" + }, { "fileMatch": "vscode://defaultsettings/*.json", "url": "vscode://schemas/settings/default" @@ -78,6 +83,10 @@ "fileMatch": "%APP_SETTINGS_HOME%/settings.json", "url": "vscode://schemas/settings/user" }, + { + "fileMatch": "%APP_SETTINGS_HOME%/profiles/*/settings.json", + "url": "vscode://schemas/settings/profile" + }, { "fileMatch": "%MACHINE_SETTINGS_HOME%/settings.json", "url": "vscode://schemas/settings/machine" @@ -114,6 +123,10 @@ "fileMatch": "%APP_SETTINGS_HOME%/snippets/*.json", "url": "vscode://schemas/snippets" }, + { + "fileMatch": "%APP_SETTINGS_HOME%/profiles/*/snippets/.json", + "url": "vscode://schemas/snippets" + }, { "fileMatch": "%APP_SETTINGS_HOME%/sync/snippets/preview/*.json", "url": "vscode://schemas/snippets" 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..681ca6105cf --- /dev/null +++ b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json @@ -0,0 +1,196 @@ +{ + "$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" + ] + } + } + } + ] + } + } + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } + } + } + } + } + }, + "codespaces": { + "type": "object", + "additionalProperties": true, + "description": "Codespaces-specific configuration.", + "deprecated": true, + "deprecationMessage": "Use 'customizations/codespaces' instead" + } + } +} diff --git a/extensions/configuration-editing/schemas/devContainer.schema.generated.json b/extensions/configuration-editing/schemas/devContainer.schema.generated.json index 4ae5033f3f1..f94a40021e1 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.generated.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.generated.json @@ -62,24 +62,6 @@ ] } }, - "containerEnv": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Container environment variables." - }, - "containerUser": { - "type": "string", - "description": "The user the container will be started with. The default is the user on the Docker image." - }, - "mounts": { - "type": "array", - "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", - "items": { - "type": "string" - } - }, "runArgs": { "type": "array", "description": "The arguments required when starting in the container.", @@ -278,6 +260,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -600,6 +659,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -672,24 +738,6 @@ ] } }, - "containerEnv": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Container environment variables." - }, - "containerUser": { - "type": "string", - "description": "The user the container will be started with. The default is the user on the Docker image." - }, - "mounts": { - "type": "array", - "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", - "items": { - "type": "string" - } - }, "runArgs": { "type": "array", "description": "The arguments required when starting in the container.", @@ -888,6 +936,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -1210,6 +1335,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -1248,24 +1380,6 @@ ] } }, - "containerEnv": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Container environment variables." - }, - "containerUser": { - "type": "string", - "description": "The user the container will be started with. The default is the user on the Docker image." - }, - "mounts": { - "type": "array", - "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", - "items": { - "type": "string" - } - }, "runArgs": { "type": "array", "description": "The arguments required when starting in the container.", @@ -1464,6 +1578,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -1786,6 +1977,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -2014,6 +2212,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -2336,6 +2611,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -2529,6 +2811,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -2851,6 +3210,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false diff --git a/extensions/configuration-editing/schemas/devContainer.schema.src.json b/extensions/configuration-editing/schemas/devContainer.schema.src.json index 73456101bb9..f908f29ac59 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.src.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.src.json @@ -177,6 +177,55 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/Mount" + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ "SYS_PTRACE" ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ "seccomp=unconfined" ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -501,6 +550,13 @@ ] } } + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } } } @@ -529,24 +585,6 @@ ] } }, - "containerEnv": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Container environment variables." - }, - "containerUser": { - "type": "string", - "description": "The user the container will be started with. The default is the user on the Docker image." - }, - "mounts": { - "type": "array", - "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", - "items": { - "type": "string" - } - }, "runArgs": { "type": "array", "description": "The arguments required when starting in the container.", @@ -728,6 +766,33 @@ "service", "workspaceFolder" ] + }, + "Mount": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false } }, "oneOf": [ 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 a90364ad93e..224a57370b4 100644 --- a/extensions/configuration-editing/src/configurationEditingMain.ts +++ b/extensions/configuration-editing/src/configurationEditingMain.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getLocation, JSONPath, parse, visit } from 'jsonc-parser'; +import { getLocation, JSONPath, parse, visit, Location } from 'jsonc-parser'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { SettingsDocument } from './settingsDocumentHelper'; @@ -39,9 +39,11 @@ function registerVariableCompletions(pattern: string): vscode.Disposable { return vscode.languages.registerCompletionItemProvider({ language: 'jsonc', pattern }, { provideCompletionItems(document, position, _token) { const location = getLocation(document.getText(), document.offsetAt(position)); - if (!location.isAtPropertyKey && location.previousNode && location.previousNode.type === 'string') { - const indexOf$ = document.lineAt(position.line).text.lastIndexOf('$', position.character); - const startPosition = indexOf$ >= 0 ? new vscode.Position(position.line, indexOf$) : position; + if (isCompletingInsidePropertyStringValue(document, location, 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); + } return [ { label: 'workspaceFolder', detail: localize('workspaceFolder', "The path of the folder opened in VS Code") }, @@ -61,7 +63,7 @@ function registerVariableCompletions(pattern: string): vscode.Disposable { { label: 'extensionInstallFolder', detail: localize('extensionInstallFolder', "The path where an an extension is installed."), param: 'publisher.extension' }, ].map(variable => ({ label: `\${${variable.label}}`, - range: new vscode.Range(startPosition, position), + range, insertText: variable.param ? new vscode.SnippetString(`\${${variable.label}:`).appendPlaceholder(variable.param).appendText('}') : (`\${${variable.label}}`), detail: variable.detail })); @@ -72,6 +74,18 @@ function registerVariableCompletions(pattern: string): vscode.Disposable { }); } +function isCompletingInsidePropertyStringValue(document: vscode.TextDocument, location: Location, pos: vscode.Position) { + if (location.isAtPropertyKey) { + return false; + } + const previousNode = location.previousNode; + if (previousNode && previousNode.type === 'string') { + const offset = document.offsetAt(pos); + return offset > previousNode.offset && offset < previousNode.offset + previousNode.length; + } + return false; +} + interface IExtensionsContent { recommendations: string[]; } @@ -84,8 +98,8 @@ function registerExtensionsCompletionsInExtensionsDocument(): vscode.Disposable return vscode.languages.registerCompletionItemProvider({ pattern: '**/extensions.json' }, { provideCompletionItems(document, position, _token) { const location = getLocation(document.getText(), document.offsetAt(position)); - const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position); if (location.path[0] === 'recommendations') { + const range = getReplaceRange(document, location, position); const extensionsContent = parse(document.getText()); return provideInstalledExtensionProposals(extensionsContent && extensionsContent.recommendations || [], '', range, false); } @@ -98,8 +112,8 @@ function registerExtensionsCompletionsInWorkspaceConfigurationDocument(): vscode return vscode.languages.registerCompletionItemProvider({ pattern: '**/*.code-workspace' }, { provideCompletionItems(document, position, _token) { const location = getLocation(document.getText(), document.offsetAt(position)); - const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position); if (location.path[0] === 'extensions' && location.path[1] === 'recommendations') { + const range = getReplaceRange(document, location, position); const extensionsContent = parse(document.getText())['extensions']; return provideInstalledExtensionProposals(extensionsContent && extensionsContent.recommendations || [], '', range, false); } @@ -108,6 +122,17 @@ function registerExtensionsCompletionsInWorkspaceConfigurationDocument(): vscode }); } +function getReplaceRange(document: vscode.TextDocument, location: Location, position: vscode.Position) { + const node = location.previousNode; + if (node) { + const nodeStart = document.positionAt(node.offset), nodeEnd = document.positionAt(node.offset + node.length); + if (nodeStart.isBeforeOrEqual(position) && nodeEnd.isAfterOrEqual(position)) { + return new vscode.Range(nodeStart, nodeEnd); + } + } + return new vscode.Range(position, position); +} + vscode.languages.registerDocumentSymbolProvider({ pattern: '**/launch.json', language: 'jsonc' }, { provideDocumentSymbols(document: vscode.TextDocument, _token: vscode.CancellationToken): vscode.ProviderResult { const result: vscode.SymbolInformation[] = []; @@ -180,28 +205,11 @@ function registerContextKeyCompletions(): vscode.Disposable { } } - if (!isValidLocation) { + if (!isValidLocation || !isCompletingInsidePropertyStringValue(document, location, position)) { return; } - // for JSON everything with quotes is a word - const jsonWord = document.getWordRangeAtPosition(position); - if (!jsonWord || jsonWord.start.isEqual(position) || jsonWord.end.isEqual(position)) { - // we aren't inside a "JSON word" or on its quotes - return; - } - - let replacing: vscode.Range | undefined; - if (jsonWord.end.character - jsonWord.start.character === 2 || document.getWordRangeAtPosition(position, /\s+/)) { - // empty json word or on whitespace - replacing = new vscode.Range(position, position); - } else { - replacing = document.getWordRangeAtPosition(position, /[a-zA-Z.]+/); - } - - if (!replacing) { - return; - } + const replacing = document.getWordRangeAtPosition(position, /[a-zA-Z.]+/) || new vscode.Range(position, position); const inserting = replacing.with(undefined, position); const data = await vscode.commands.executeCommand('getContextKeyInfo'); diff --git a/extensions/configuration-editing/src/extensionsProposals.ts b/extensions/configuration-editing/src/extensionsProposals.ts index 458f3be4ce5..ab648e05f3c 100644 --- a/extensions/configuration-editing/src/extensionsProposals.ts +++ b/extensions/configuration-editing/src/extensionsProposals.ts @@ -8,7 +8,7 @@ import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -export function provideInstalledExtensionProposals(existing: string[], additionalText: string, range: vscode.Range, includeBuiltinExtensions: boolean): vscode.ProviderResult { +export async function provideInstalledExtensionProposals(existing: string[], additionalText: string, range: vscode.Range, includeBuiltinExtensions: boolean): Promise { if (Array.isArray(existing)) { const extensions = includeBuiltinExtensions ? vscode.extensions.all : vscode.extensions.all.filter(e => !(e.id.startsWith('vscode.') || e.id === 'Microsoft.vscode-markdown')); const knownExtensionProposals = extensions.filter(e => existing.indexOf(e.id) === -1); @@ -30,10 +30,10 @@ export function provideInstalledExtensionProposals(existing: string[], additiona return [example]; } } - return undefined; + return []; } -export function provideWorkspaceTrustExtensionProposals(existing: string[], range: vscode.Range): vscode.ProviderResult { +export async function provideWorkspaceTrustExtensionProposals(existing: string[], range: vscode.Range): Promise { if (Array.isArray(existing)) { const extensions = vscode.extensions.all.filter(e => e.packageJSON.main); const extensionProposals = extensions.filter(e => existing.indexOf(e.id) === -1); @@ -56,5 +56,5 @@ export function provideWorkspaceTrustExtensionProposals(existing: string[], rang } } - return undefined; + return []; } diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index d5928592b5a..ab41c8220c2 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -15,32 +15,27 @@ export class SettingsDocument { constructor(private document: vscode.TextDocument) { } - public provideCompletionItems(position: vscode.Position, _token: vscode.CancellationToken): vscode.ProviderResult { + public async provideCompletionItems(position: vscode.Position, _token: vscode.CancellationToken): Promise { const location = getLocation(this.document.getText(), this.document.offsetAt(position)); - const range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position); // window.title if (location.path[0] === 'window.title') { - return this.provideWindowTitleCompletionItems(location, range); + return this.provideWindowTitleCompletionItems(location, position); } // files.association if (location.path[0] === 'files.associations') { - return this.provideFilesAssociationsCompletionItems(location, range); + return this.provideFilesAssociationsCompletionItems(location, position); } // files.exclude, search.exclude if (location.path[0] === 'files.exclude' || location.path[0] === 'search.exclude') { - return this.provideExcludeCompletionItems(location, range); + return this.provideExcludeCompletionItems(location, position); } // files.defaultLanguage if (location.path[0] === 'files.defaultLanguage') { - return this.provideLanguageCompletionItems(location, range).then(items => { - - // Add special item '${activeEditorLanguage}' - return [this.newSimpleCompletionItem(JSON.stringify('${activeEditorLanguage}'), range, localize('activeEditor', "Use the language of the currently active text editor if any")), ...items]; - }); + return this.provideLanguageCompletionItems(location, position); } // settingsSync.ignoredExtensions @@ -49,6 +44,7 @@ export class SettingsDocument { try { ignoredExtensions = parse(this.document.getText())['settingsSync.ignoredExtensions']; } catch (e) {/* ignore error */ } + const range = this.getReplaceRange(location, position); return provideInstalledExtensionProposals(ignoredExtensions, '', range, true); } @@ -58,44 +54,85 @@ export class SettingsDocument { try { alreadyConfigured = Object.keys(parse(this.document.getText())['remote.extensionKind']); } catch (e) {/* ignore error */ } - return provideInstalledExtensionProposals(alreadyConfigured, `: [\n\t"ui"\n]`, range, true); + const range = this.getReplaceRange(location, position); + return provideInstalledExtensionProposals(alreadyConfigured, location.previousNode ? '' : `: [\n\t"ui"\n]`, range, true); } // remote.portsAttributes if (location.path[0] === 'remote.portsAttributes' && location.path.length === 2 && location.isAtPropertyKey) { - return this.providePortsAttributesCompletionItem(range); + return this.providePortsAttributesCompletionItem(this.getReplaceRange(location, position)); } return this.provideLanguageOverridesCompletionItems(location, position); } - private provideWindowTitleCompletionItems(_location: Location, range: vscode.Range): vscode.ProviderResult { - const completions: vscode.CompletionItem[] = []; - - completions.push(this.newSimpleCompletionItem('${activeEditorShort}', range, localize('activeEditorShort', "the file name (e.g. myFile.txt)"))); - completions.push(this.newSimpleCompletionItem('${activeEditorMedium}', range, localize('activeEditorMedium', "the path of the file relative to the workspace folder (e.g. myFolder/myFileFolder/myFile.txt)"))); - completions.push(this.newSimpleCompletionItem('${activeEditorLong}', range, localize('activeEditorLong', "the full path of the file (e.g. /Users/Development/myFolder/myFileFolder/myFile.txt)"))); - completions.push(this.newSimpleCompletionItem('${activeFolderShort}', range, localize('activeFolderShort', "the name of the folder the file is contained in (e.g. myFileFolder)"))); - completions.push(this.newSimpleCompletionItem('${activeFolderMedium}', range, localize('activeFolderMedium', "the path of the folder the file is contained in, relative to the workspace folder (e.g. myFolder/myFileFolder)"))); - completions.push(this.newSimpleCompletionItem('${activeFolderLong}', range, localize('activeFolderLong', "the full path of the folder the file is contained in (e.g. /Users/Development/myFolder/myFileFolder)"))); - completions.push(this.newSimpleCompletionItem('${rootName}', range, localize('rootName', "name of the workspace (e.g. myFolder or myWorkspace)"))); - completions.push(this.newSimpleCompletionItem('${rootPath}', range, localize('rootPath', "file path of the workspace (e.g. /Users/Development/myWorkspace)"))); - completions.push(this.newSimpleCompletionItem('${folderName}', range, localize('folderName', "name of the workspace folder the file is contained in (e.g. myFolder)"))); - completions.push(this.newSimpleCompletionItem('${folderPath}', range, localize('folderPath', "file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)"))); - completions.push(this.newSimpleCompletionItem('${appName}', range, localize('appName', "e.g. VS Code"))); - completions.push(this.newSimpleCompletionItem('${remoteName}', range, localize('remoteName', "e.g. SSH"))); - completions.push(this.newSimpleCompletionItem('${dirty}', range, localize('dirty', "an indicator for when the active editor has unsaved changes"))); - completions.push(this.newSimpleCompletionItem('${separator}', range, localize('separator', "a conditional separator (' - ') that only shows when surrounded by variables with values"))); - - return Promise.resolve(completions); + private getReplaceRange(location: Location, position: vscode.Position) { + const node = location.previousNode; + if (node) { + const nodeStart = this.document.positionAt(node.offset), nodeEnd = this.document.positionAt(node.offset + node.length); + if (nodeStart.isBeforeOrEqual(position) && nodeEnd.isAfterOrEqual(position)) { + return new vscode.Range(nodeStart, nodeEnd); + } + } + return new vscode.Range(position, position); } - private provideFilesAssociationsCompletionItems(location: Location, range: vscode.Range): vscode.ProviderResult { + private isCompletingPropertyValue(location: Location, pos: vscode.Position) { + if (location.isAtPropertyKey) { + return false; + } + const previousNode = location.previousNode; + if (previousNode) { + const offset = this.document.offsetAt(pos); + return offset >= previousNode.offset && offset <= previousNode.offset + previousNode.length; + } + return true; + } + + private async provideWindowTitleCompletionItems(location: Location, pos: vscode.Position): Promise { + const completions: vscode.CompletionItem[] = []; + + if (!this.isCompletingPropertyValue(location, pos)) { + return completions; + } + + 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); + } + + const getText = (variable: string) => { + const text = '${' + variable + '}'; + return location.previousNode ? text : JSON.stringify(text); + }; + + + completions.push(this.newSimpleCompletionItem(getText('activeEditorShort'), range, localize('activeEditorShort', "the file name (e.g. myFile.txt)"))); + completions.push(this.newSimpleCompletionItem(getText('activeEditorMedium'), range, localize('activeEditorMedium', "the path of the file relative to the workspace folder (e.g. myFolder/myFileFolder/myFile.txt)"))); + completions.push(this.newSimpleCompletionItem(getText('activeEditorLong'), range, localize('activeEditorLong', "the full path of the file (e.g. /Users/Development/myFolder/myFileFolder/myFile.txt)"))); + completions.push(this.newSimpleCompletionItem(getText('activeFolderShort'), range, localize('activeFolderShort', "the name of the folder the file is contained in (e.g. myFileFolder)"))); + completions.push(this.newSimpleCompletionItem(getText('activeFolderMedium'), range, localize('activeFolderMedium', "the path of the folder the file is contained in, relative to the workspace folder (e.g. myFolder/myFileFolder)"))); + completions.push(this.newSimpleCompletionItem(getText('activeFolderLong'), range, localize('activeFolderLong', "the full path of the folder the file is contained in (e.g. /Users/Development/myFolder/myFileFolder)"))); + completions.push(this.newSimpleCompletionItem(getText('rootName'), range, localize('rootName', "name of the workspace (e.g. myFolder or myWorkspace)"))); + completions.push(this.newSimpleCompletionItem(getText('rootPath'), range, localize('rootPath', "file path of the workspace (e.g. /Users/Development/myWorkspace)"))); + completions.push(this.newSimpleCompletionItem(getText('folderName'), range, localize('folderName', "name of the workspace folder the file is contained in (e.g. myFolder)"))); + completions.push(this.newSimpleCompletionItem(getText('folderPath'), range, localize('folderPath', "file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)"))); + completions.push(this.newSimpleCompletionItem(getText('appName'), range, localize('appName', "e.g. VS Code"))); + completions.push(this.newSimpleCompletionItem(getText('remoteName'), range, localize('remoteName', "e.g. SSH"))); + completions.push(this.newSimpleCompletionItem(getText('dirty'), range, localize('dirty', "an indicator for when the active editor has unsaved changes"))); + completions.push(this.newSimpleCompletionItem(getText('separator'), range, localize('separator', "a conditional separator (' - ') that only shows when surrounded by variables with values"))); + + return completions; + } + + private async provideFilesAssociationsCompletionItems(location: Location, position: vscode.Position): Promise { const completions: vscode.CompletionItem[] = []; if (location.path.length === 2) { // Key - if (!location.isAtPropertyKey || location.path[1] === '') { + if (location.path[1] === '') { + const range = this.getReplaceRange(location, position); + completions.push(this.newSnippetCompletionItem({ label: localize('assocLabelFile', "Files with Extension"), documentation: localize('assocDescriptionFile', "Map all files matching the glob pattern in their filename to the language with the given identifier."), @@ -109,68 +146,68 @@ export class SettingsDocument { snippet: location.isAtPropertyKey ? '"/${1:path to file}/*.${2:extension}": "${3:language}"' : '{ "/${1:path to file}/*.${2:extension}": "${3:language}" }', range })); - } else { + } else if (this.isCompletingPropertyValue(location, position)) { // Value - return this.provideLanguageCompletionItemsForLanguageOverrides(location, range); + return this.provideLanguageCompletionItemsForLanguageOverrides(this.getReplaceRange(location, position)); } } - return Promise.resolve(completions); + return completions; } - private provideExcludeCompletionItems(location: Location, range: vscode.Range): vscode.ProviderResult { + private async provideExcludeCompletionItems(location: Location, position: vscode.Position): Promise { const completions: vscode.CompletionItem[] = []; // Key - if (location.path.length === 1) { + if (location.path.length === 1 || (location.path.length === 2 && location.path[1] === '')) { + const range = this.getReplaceRange(location, position); + completions.push(this.newSnippetCompletionItem({ label: localize('fileLabel', "Files by Extension"), documentation: localize('fileDescription', "Match all files of a specific file extension."), - snippet: location.isAtPropertyKey ? '"**/*.${1:extension}": true' : '{ "**/*.${1:extension}": true }', + snippet: location.path.length === 2 ? '"**/*.${1:extension}": true' : '{ "**/*.${1:extension}": true }', range })); completions.push(this.newSnippetCompletionItem({ label: localize('filesLabel', "Files with Multiple Extensions"), documentation: localize('filesDescription', "Match all files with any of the file extensions."), - snippet: location.isAtPropertyKey ? '"**/*.{ext1,ext2,ext3}": true' : '{ "**/*.{ext1,ext2,ext3}": true }', + snippet: location.path.length === 2 ? '"**/*.{ext1,ext2,ext3}": true' : '{ "**/*.{ext1,ext2,ext3}": true }', range })); completions.push(this.newSnippetCompletionItem({ label: localize('derivedLabel', "Files with Siblings by Name"), documentation: localize('derivedDescription', "Match files that have siblings with the same name but a different extension."), - snippet: location.isAtPropertyKey ? '"**/*.${1:source-extension}": { "when": "$(basename).${2:target-extension}" }' : '{ "**/*.${1:source-extension}": { "when": "$(basename).${2:target-extension}" } }', + snippet: location.path.length === 2 ? '"**/*.${1:source-extension}": { "when": "$(basename).${2:target-extension}" }' : '{ "**/*.${1:source-extension}": { "when": "$(basename).${2:target-extension}" } }', range })); completions.push(this.newSnippetCompletionItem({ label: localize('topFolderLabel', "Folder by Name (Top Level)"), documentation: localize('topFolderDescription', "Match a top level folder with a specific name."), - snippet: location.isAtPropertyKey ? '"${1:name}": true' : '{ "${1:name}": true }', + snippet: location.path.length === 2 ? '"${1:name}": true' : '{ "${1:name}": true }', range })); completions.push(this.newSnippetCompletionItem({ label: localize('topFoldersLabel', "Folders with Multiple Names (Top Level)"), documentation: localize('topFoldersDescription', "Match multiple top level folders."), - snippet: location.isAtPropertyKey ? '"{folder1,folder2,folder3}": true' : '{ "{folder1,folder2,folder3}": true }', + snippet: location.path.length === 2 ? '"{folder1,folder2,folder3}": true' : '{ "{folder1,folder2,folder3}": true }', range })); completions.push(this.newSnippetCompletionItem({ label: localize('folderLabel', "Folder by Name (Any Location)"), documentation: localize('folderDescription', "Match a folder with a specific name in any location."), - snippet: location.isAtPropertyKey ? '"**/${1:name}": true' : '{ "**/${1:name}": true }', + snippet: location.path.length === 2 ? '"**/${1:name}": true' : '{ "**/${1:name}": true }', range })); } // Value - else { - completions.push(this.newSimpleCompletionItem('false', range, localize('falseDescription', "Disable the pattern."))); - completions.push(this.newSimpleCompletionItem('true', range, localize('trueDescription', "Enable the pattern."))); - + else if (location.path.length === 2 && this.isCompletingPropertyValue(location, position)) { + const range = this.getReplaceRange(location, position); completions.push(this.newSnippetCompletionItem({ label: localize('derivedLabel', "Files with Siblings by Name"), documentation: localize('siblingsDescription', "Match files that have siblings with the same name but a different extension."), @@ -179,15 +216,22 @@ export class SettingsDocument { })); } - return Promise.resolve(completions); + return completions; } - private provideLanguageCompletionItems(_location: Location, range: vscode.Range, formatFunc: (string: string) => string = (l) => JSON.stringify(l)): Thenable { - return vscode.languages.getLanguages() - .then(languages => languages.map(l => this.newSimpleCompletionItem(formatFunc(l), range))); + private async provideLanguageCompletionItems(location: Location, position: vscode.Position): Promise { + if (location.path.length === 1 && this.isCompletingPropertyValue(location, position)) { + const range = this.getReplaceRange(location, position); + const languages = await vscode.languages.getLanguages(); + return [ + this.newSimpleCompletionItem(JSON.stringify('${activeEditorLanguage}'), range, localize('activeEditor', "Use the language of the currently active text editor if any")), + ...languages.map(l => this.newSimpleCompletionItem(JSON.stringify(l), range)) + ]; + } + return []; } - private async provideLanguageCompletionItemsForLanguageOverrides(_location: Location, range: vscode.Range): Promise { + private async provideLanguageCompletionItemsForLanguageOverrides(range: vscode.Range): Promise { const languages = await vscode.languages.getLanguages(); const completionItems = []; for (const language of languages) { @@ -200,7 +244,7 @@ export class SettingsDocument { } private async provideLanguageOverridesCompletionItems(location: Location, position: vscode.Position): Promise { - if (location.path.length === 1 && location.previousNode && typeof location.previousNode.value === 'string' && location.previousNode.value.startsWith('[')) { + if (location.path.length === 1 && location.isAtPropertyKey && location.previousNode && typeof location.previousNode.value === 'string' && location.previousNode.value.startsWith('[')) { const startPosition = this.document.positionAt(location.previousNode.offset + 1); const endPosition = startPosition.translate(undefined, location.previousNode.value.length); const donotSuggestLanguages: string[] = []; diff --git a/extensions/configuration-editing/src/test/completion.test.ts b/extensions/configuration-editing/src/test/completion.test.ts new file mode 100644 index 00000000000..e5aec5fc46a --- /dev/null +++ b/extensions/configuration-editing/src/test/completion.test.ts @@ -0,0 +1,594 @@ +/*--------------------------------------------------------------------------------------------- + * 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 assert from 'assert'; +import { promises as fs } from 'fs'; +import * as path from 'path'; +import * as os from 'os'; +import 'mocha'; + + +const testFolder = fs.mkdtemp(path.join(os.tmpdir(), 'conf-editing-')); + +suite('Completions in settings.json', () => { + const testFile = 'settings.json'; + + test('window.title', async () => { + { // inserting after text + const content = [ + '{', + ' "window.title": "custom|"', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "window.title": "custom${activeEditorShort}"', + '}', + ].join('\n'); + const expected = { label: '${activeEditorShort}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { // inserting before a variable + const content = [ + '{', + ' "window.title": "|${activeEditorShort}"', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "window.title": "${folderPath}${activeEditorShort}"', + '}', + ].join('\n'); + const expected = { label: '${folderPath}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { // inserting after a variable + const content = [ + '{', + ' "window.title": "${activeEditorShort}|"', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "window.title": "${activeEditorShort}${folderPath}"', + '}', + ].join('\n'); + const expected = { label: '${folderPath}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { // replacing an variable + const content = [ + '{', + ' "window.title": "${a|ctiveEditorShort}"', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "window.title": "${activeEditorMedium}"', + '}', + ].join('\n'); + 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 = [ + '{', + ' "window.title": |', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "window.title": "${activeEditorMedium}"', + '}', + ].join('\n'); + const expected = { label: '"${activeEditorMedium}"', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { // no proposals after literal + const content = [ + '{', + ' "window.title": "${activeEditorShort}" |', + '}', + ].join('\n'); + const expected = { label: '${activeEditorMedium}', notAvailable: true }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); + + test('files.associations', async () => { + { + const content = [ + '{', + ' "files.associations": {', + ' |', + ' }', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "files.associations": {', + ' "*.${1:extension}": "${2:language}"', + ' }', + '}', + ].join('\n'); + const expected = { label: 'Files with Extension', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { + const content = [ + '{', + ' "files.associations": {', + ' |', + ' }', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "files.associations": {', + ' "/${1:path to file}/*.${2:extension}": "${3:language}"', + ' }', + '}', + ].join('\n'); + const expected = { label: 'Files with Path', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { + const content = [ + '{', + ' "files.associations": {', + ' "*.extension": "|bat"', + ' }', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "files.associations": {', + ' "*.extension": "json"', + ' }', + '}', + ].join('\n'); + const expected = { label: '"json"', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { + const content = [ + '{', + ' "files.associations": {', + ' "*.extension": "bat"|', + ' }', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "files.associations": {', + ' "*.extension": "json"', + ' }', + '}', + ].join('\n'); + const expected = { label: '"json"', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { + const content = [ + '{', + ' "files.associations": {', + ' "*.extension": "bat" |', + ' }', + '}', + ].join('\n'); + const expected = { label: '"json"', notAvailable: true }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); + test('files.exclude', async () => { + { + const content = [ + '{', + ' "files.exclude": {', + ' |', + ' }', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "files.exclude": {', + ' "**/*.${1:extension}": true', + ' }', + '}', + ].join('\n'); + const expected = { label: 'Files by Extension', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { + const content = [ + '{', + ' "files.exclude": {', + ' "**/*.extension": |true', + ' }', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "files.exclude": {', + ' "**/*.extension": { "when": "$(basename).${1:extension}" }', + ' }', + '}', + ].join('\n'); + const expected = { label: 'Files with Siblings by Name', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); + test('files.defaultLanguage', async () => { + { + const content = [ + '{', + ' "files.defaultLanguage": "json|"', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "files.defaultLanguage": "jsonc"', + '}', + ].join('\n'); + const expected = { label: '"jsonc"', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { + const content = [ + '{', + ' "files.defaultLanguage": |', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "files.defaultLanguage": "jsonc"', + '}', + ].join('\n'); + const expected = { label: '"jsonc"', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); + test('remote.extensionKind', async () => { + { + const content = [ + '{', + '\t"remote.extensionKind": {', + '\t\t|', + '\t}', + '}', + ].join('\n'); + const expected = { label: 'vscode.npm' }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); + test('remote.portsAttributes', async () => { + { + const content = [ + '{', + ' "remote.portsAttributes": {', + ' |', + ' }', + '}', + ].join('\n'); + const expected = { label: '"3000"' }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); +}); + +suite('Completions in extensions.json', () => { + const testFile = 'extensions.json'; + test('change recommendation', async () => { + { + const content = [ + '{', + ' "recommendations": [', + ' "|a.b"', + ' ]', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "recommendations": [', + ' "ms-vscode.js-debug"', + ' ]', + '}', + ].join('\n'); + const expected = { label: 'ms-vscode.js-debug', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); + test('add recommendation', async () => { + { + const content = [ + '{', + ' "recommendations": [', + ' |', + ' ]', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "recommendations": [', + ' "ms-vscode.js-debug"', + ' ]', + '}', + ].join('\n'); + const expected = { label: 'ms-vscode.js-debug', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); +}); + +suite('Completions in launch.json', () => { + const testFile = 'launch.json'; + test('variable completions', async () => { + { + const content = [ + '{', + ' "version": "0.2.0",', + ' "configurations": [', + ' {', + ' "name": "Run Extension",', + ' "type": "extensionHost",', + ' "preLaunchTask": "${|defaultBuildTask}"', + ' }', + ' ]', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "version": "0.2.0",', + ' "configurations": [', + ' {', + ' "name": "Run Extension",', + ' "type": "extensionHost",', + ' "preLaunchTask": "${cwd}"', + ' }', + ' ]', + '}', + ].join('\n'); + const expected = { label: '${cwd}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { + const content = [ + '{', + ' "version": "0.2.0",', + ' "configurations": [', + ' {', + ' "name": "Run Extension",', + ' "type": "extensionHost",', + ' "preLaunchTask": "|${defaultBuildTask}"', + ' }', + ' ]', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "version": "0.2.0",', + ' "configurations": [', + ' {', + ' "name": "Run Extension",', + ' "type": "extensionHost",', + ' "preLaunchTask": "${cwd}${defaultBuildTask}"', + ' }', + ' ]', + '}', + ].join('\n'); + 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); + } + }); +}); + +suite('Completions in tasks.json', () => { + const testFile = 'tasks.json'; + test('variable completions', async () => { + { + const content = [ + '{', + ' "version": "0.2.0",', + ' "tasks": [', + ' {', + ' "type": "shell",', + ' "command": "${|defaultBuildTask}"', + ' }', + ' ]', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "version": "0.2.0",', + ' "tasks": [', + ' {', + ' "type": "shell",', + ' "command": "${cwd}"', + ' }', + ' ]', + '}', + ].join('\n'); + const expected = { label: '${cwd}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + { + const content = [ + '{', + ' "version": "0.2.0",', + ' "tasks": [', + ' {', + ' "type": "shell",', + ' "command": "${defaultBuildTask}|"', + ' }', + ' ]', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "version": "0.2.0",', + ' "tasks": [', + ' {', + ' "type": "shell",', + ' "command": "${defaultBuildTask}${cwd}"', + ' }', + ' ]', + '}', + ].join('\n'); + const expected = { label: '${cwd}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); +}); + +suite('Completions in keybindings.json', () => { + const testFile = 'keybindings.json'; + test('context key insertion', async () => { + { + const content = [ + '[', + ' {', + ' "key": "ctrl+k ctrl+,",', + ' "command": "editor.jumpToNextFold",', + ' "when": "|"', + ' }', + ']', + ].join('\n'); + const resultText = [ + '[', + ' {', + ' "key": "ctrl+k ctrl+,",', + ' "command": "editor.jumpToNextFold",', + ' "when": "resourcePath"', + ' }', + ']', + ].join('\n'); + const expected = { label: 'resourcePath', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); + + test('context key replace', async () => { + { + const content = [ + '[', + ' {', + ' "key": "ctrl+k ctrl+,",', + ' "command": "editor.jumpToNextFold",', + ' "when": "resou|rcePath"', + ' }', + ']', + ].join('\n'); + const resultText = [ + '[', + ' {', + ' "key": "ctrl+k ctrl+,",', + ' "command": "editor.jumpToNextFold",', + ' "when": "resource"', + ' }', + ']', + ].join('\n'); + const expected = { label: 'resource', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } + }); +}); + +interface ItemDescription { + label: string; + resultText?: string; + notAvailable?: boolean; +} + +async function testCompletion(testFileName: string, languageId: string, content: string, expected: ItemDescription) { + + const offset = content.indexOf('|'); + content = content.substring(0, offset) + content.substring(offset + 1); + + const docUri = vscode.Uri.file(path.join(await testFolder, testFileName)); + await fs.writeFile(docUri.fsPath, content); + + const editor = await setTestContent(docUri, languageId, content); + const position = editor.document.positionAt(offset); + + // Executing the command `vscode.executeCompletionItemProvider` to simulate triggering completion + const actualCompletions = (await vscode.commands.executeCommand('vscode.executeCompletionItemProvider', docUri, position)) as vscode.CompletionList; + + const matches = actualCompletions.items.filter(completion => { + return completion.label === expected.label; + }); + if (expected.notAvailable) { + assert.strictEqual(matches.length, 0, `${expected.label} should not existing is results`); + } else { + assert.strictEqual(matches.length, 1, `${expected.label} should only existing once: Actual: ${actualCompletions.items.map(c => c.label).join(', ')}`); + + if (expected.resultText) { + const match = matches[0]; + if (match.range && match.insertText) { + const range = match.range instanceof vscode.Range ? match.range : match.range.replacing; + const text = typeof match.insertText === 'string' ? match.insertText : match.insertText.value; + + await editor.edit(eb => eb.replace(range, text)); + assert.strictEqual(editor.document.getText(), expected.resultText); + } else { + assert.fail(`Range or insertText missing`); + } + } + } +} + +async function setTestContent(docUri: vscode.Uri, languageId: string, content: string): Promise { + const ext = vscode.extensions.getExtension('vscode.configuration-editing')!; + await ext.activate(); + + const doc = await vscode.workspace.openTextDocument(docUri); + await vscode.languages.setTextDocumentLanguage(doc, languageId); + const editor = await vscode.window.showTextDocument(doc); + + const fullRange = new vscode.Range(new vscode.Position(0, 0), doc.positionAt(doc.getText().length)); + await editor.edit(eb => eb.replace(fullRange, content)); + return editor; + +} diff --git a/extensions/vscode-notebook-tests/src/index.ts b/extensions/configuration-editing/src/test/index.ts similarity index 81% rename from extensions/vscode-notebook-tests/src/index.ts rename to extensions/configuration-editing/src/test/index.ts index 2f8fb129206..beec6063928 100644 --- a/extensions/vscode-notebook-tests/src/index.ts +++ b/extensions/configuration-editing/src/test/index.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ const path = require('path'); -const testRunner = require('../../../test/integration/electron/testrunner'); +const testRunner = require('../../../../test/integration/electron/testrunner'); const options: any = { ui: 'tdd', @@ -17,11 +17,11 @@ const options: any = { // for the test results file name let suite = ''; if (process.env.VSCODE_BROWSER) { - suite = `${process.env.VSCODE_BROWSER} Browser Integration Notebook Tests`; + suite = `${process.env.VSCODE_BROWSER} Browser Integration Configuration-Editing Tests`; } else if (process.env.REMOTE_VSCODE) { - suite = 'Remote Integration Notebook Tests'; + suite = 'Remote Integration Configuration-Editing Tests'; } else { - suite = 'Integration Notebook Tests'; + suite = 'Integration Configuration-Editing Tests'; } if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { diff --git a/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock index f7ac959fc09..5bb8132d373 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.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== diff --git a/extensions/cpp/build/update-grammars.js b/extensions/cpp/build/update-grammars.js index dd265436a28..983e61488ef 100644 --- a/extensions/cpp/build/update-grammars.js +++ b/extensions/cpp/build/update-grammars.js @@ -6,12 +6,16 @@ var updateGrammar = require('vscode-grammar-updater'); -updateGrammar.update('jeff-hykin/cpp-textmate-grammar', 'syntaxes/c.tmLanguage.json', './syntaxes/c.tmLanguage.json', undefined, 'master', 'source/languages/cpp/'); -updateGrammar.update('jeff-hykin/cpp-textmate-grammar', 'syntaxes/cpp.tmLanguage.json', './syntaxes/cpp.tmLanguage.json', undefined, 'master', 'source/languages/cpp/'); -updateGrammar.update('jeff-hykin/cpp-textmate-grammar', 'syntaxes/cpp.embedded.macro.tmLanguage.json', './syntaxes/cpp.embedded.macro.tmLanguage.json', undefined, 'master', 'source/languages/cpp/'); +async function updateGrammars() { + await updateGrammar.update('jeff-hykin/better-c-syntax', 'autogenerated/c.tmLanguage.json', './syntaxes/c.tmLanguage.json', undefined, 'master'); + await updateGrammar.update('jeff-hykin/better-cpp-syntax', 'autogenerated/cpp.tmLanguage.json', './syntaxes/cpp.tmLanguage.json', undefined, 'master'); + await updateGrammar.update('jeff-hykin/better-cpp-syntax', 'autogenerated/cpp.embedded.macro.tmLanguage.json', './syntaxes/cpp.embedded.macro.tmLanguage.json', undefined, 'master'); -updateGrammar.update('NVIDIA/cuda-cpp-grammar', 'syntaxes/cuda-cpp.tmLanguage.json', './syntaxes/cuda-cpp.tmLanguage.json', undefined, 'master'); + await updateGrammar.update('NVIDIA/cuda-cpp-grammar', 'syntaxes/cuda-cpp.tmLanguage.json', './syntaxes/cuda-cpp.tmLanguage.json', undefined, 'master'); // `source.c.platform` which is still included by other grammars -updateGrammar.update('textmate/c.tmbundle', 'Syntaxes/Platform.tmLanguage', './syntaxes/platform.tmLanguage.json'); + await updateGrammar.update('textmate/c.tmbundle', 'Syntaxes/Platform.tmLanguage', './syntaxes/platform.tmLanguage.json'); +} + +updateGrammars(); diff --git a/extensions/cpp/cgmanifest.json b/extensions/cpp/cgmanifest.json index f2bf269a5f4..92d0016b0e6 100644 --- a/extensions/cpp/cgmanifest.json +++ b/extensions/cpp/cgmanifest.json @@ -4,14 +4,27 @@ "component": { "type": "git", "git": { - "name": "jeff-hykin/cpp-textmate-grammar", - "repositoryUrl": "https://github.com/jeff-hykin/cpp-textmate-grammar", - "commitHash": "db3f4e4a5d8335b2f6d689bec490c23f8313630f" + "name": "jeff-hykin/better-cpp-syntax", + "repositoryUrl": "https://github.com/jeff-hykin/better-cpp-syntax", + "commitHash": "32be139c7d3cdf07195af4b3a5c639ebf4e3b356" } }, "license": "MIT", - "version": "1.15.6", - "description": "The files syntaxes/c.json and syntaxes/c++.json were derived from https://github.com/atom/language-c which was originally converted from the C TextMate bundle https://github.com/textmate/c.tmbundle." + "version": "1.15.23", + "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." + }, + { + "component": { + "type": "git", + "git": { + "name": "jeff-hykin/better-c-syntax", + "repositoryUrl": "https://github.com/jeff-hykin/better-c-syntax", + "commitHash": "34712a6106a4ffb0a04d2fa836fd28ff6c5849a4" + } + }, + "license": "MIT", + "version": "1.13.2", + "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." }, { "component": { diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index 9a88814ff35..0f365702269 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -13,7 +13,8 @@ { "open": "{", "close": "}" }, { "open": "(", "close": ")" }, { "open": "'", "close": "'", "notIn": ["string", "comment"] }, - { "open": "\"", "close": "\"", "notIn": ["string"] } + { "open": "\"", "close": "\"", "notIn": ["string"] }, + { "open": "/*", "close": "*/", "notIn": ["string", "comment"] } ], "surroundingPairs": [ ["{", "}"], diff --git a/extensions/cpp/syntaxes/c.tmLanguage.json b/extensions/cpp/syntaxes/c.tmLanguage.json index 80852872cd8..47f73833ed2 100644 --- a/extensions/cpp/syntaxes/c.tmLanguage.json +++ b/extensions/cpp/syntaxes/c.tmLanguage.json @@ -1,10 +1,10 @@ { "information_for_contributors": [ - "This file has been converted from https://github.com/jeff-hykin/cpp-textmate-grammar/blob/master/syntaxes/c.tmLanguage.json", + "This file has been converted from https://github.com/jeff-hykin/better-c-syntax/blob/master/autogenerated/c.tmLanguage.json", "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/0ef79f098ed80ce5a86be4ed40f99ebcdbac4895", + "version": "https://github.com/jeff-hykin/better-c-syntax/commit/34712a6106a4ffb0a04d2fa836fd28ff6c5849a4", "name": "C", "scopeName": "source.c", "patterns": [ @@ -27,35 +27,28 @@ "include": "#switch_statement" }, { - "match": "\\b(break|continue|do|else|for|goto|if|_Pragma|return|while)\\b", - "name": "keyword.control.c" + "include": "#anon_pattern_1" }, { "include": "#storage_types" }, { - "match": "typedef", - "name": "keyword.other.typedef.c" + "include": "#anon_pattern_2" }, { - "match": "\\b(const|extern|register|restrict|static|volatile|inline)\\b", - "name": "storage.modifier.c" + "include": "#anon_pattern_3" }, { - "match": "\\bk[A-Z]\\w*\\b", - "name": "constant.other.variable.mac-classic.c" + "include": "#anon_pattern_4" }, { - "match": "\\bg[A-Z]\\w*\\b", - "name": "variable.other.readwrite.global.mac-classic.c" + "include": "#anon_pattern_5" }, { - "match": "\\bs[A-Z]\\w*\\b", - "name": "variable.other.readwrite.static.mac-classic.c" + "include": "#anon_pattern_6" }, { - "match": "\\b(NULL|true|false|TRUE|FALSE)\\b", - "name": "constant.language.c" + "include": "#anon_pattern_7" }, { "include": "#operators" @@ -67,6 +60,183 @@ "include": "#strings" }, { + "include": "#anon_pattern_range_1" + }, + { + "include": "#anon_pattern_range_2" + }, + { + "include": "#anon_pattern_range_3" + }, + { + "include": "#pragma-mark" + }, + { + "include": "#anon_pattern_range_4" + }, + { + "include": "#anon_pattern_range_5" + }, + { + "include": "#anon_pattern_range_6" + }, + { + "include": "#anon_pattern_8" + }, + { + "include": "#anon_pattern_9" + }, + { + "include": "#anon_pattern_10" + }, + { + "include": "#anon_pattern_11" + }, + { + "include": "#anon_pattern_12" + }, + { + "include": "#anon_pattern_13" + }, + { + "include": "#block" + }, + { + "include": "#parens" + }, + { + "include": "#anon_pattern_range_7" + }, + { + "include": "#line_continuation_character" + }, + { + "include": "#anon_pattern_range_8" + }, + { + "include": "#anon_pattern_range_9" + }, + { + "include": "#anon_pattern_14" + }, + { + "include": "#anon_pattern_15" + } + ], + "repository": { + "access-method": { + "name": "meta.function-call.member.c", + "begin": "([a-zA-Z_][a-zA-Z_0-9]*|(?<=[\\]\\)]))\\s*(?:(\\.)|(->))((?:(?:[a-zA-Z_][a-zA-Z_0-9]*)\\s*(?:(?:\\.)|(?:->)))*)\\s*([a-zA-Z_][a-zA-Z_0-9]*)(\\()", + "beginCaptures": { + "1": { + "name": "variable.object.c" + }, + "2": { + "name": "punctuation.separator.dot-access.c" + }, + "3": { + "name": "punctuation.separator.pointer-access.c" + }, + "4": { + "patterns": [ + { + "match": "\\.", + "name": "punctuation.separator.dot-access.c" + }, + { + "match": "->", + "name": "punctuation.separator.pointer-access.c" + }, + { + "match": "[a-zA-Z_][a-zA-Z_0-9]*", + "name": "variable.object.c" + }, + { + "name": "everything.else.c", + "match": ".+" + } + ] + }, + "5": { + "name": "entity.name.function.member.c" + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.c" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.c" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + "anon_pattern_1": { + "match": "\\b(break|continue|do|else|for|goto|if|_Pragma|return|while)\\b", + "name": "keyword.control.c" + }, + "anon_pattern_10": { + "match": "(?x) \\b\n(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t\n|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t\n|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t\n|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t\n|uintmax_t|uintmax_t)\n\\b", + "name": "support.type.stdint.c" + }, + "anon_pattern_11": { + "match": "\\b(noErr|kNilOptions|kInvalidID|kVariableLengthArray)\\b", + "name": "support.constant.mac-classic.c" + }, + "anon_pattern_12": { + "match": "(?x) \\b\n(AbsoluteTime|Boolean|Byte|ByteCount|ByteOffset|BytePtr|CompTimeValue|ConstLogicalAddress|ConstStrFileNameParam\n|ConstStringPtr|Duration|Fixed|FixedPtr|Float32|Float32Point|Float64|Float80|Float96|FourCharCode|Fract|FractPtr\n|Handle|ItemCount|LogicalAddress|OptionBits|OSErr|OSStatus|OSType|OSTypePtr|PhysicalAddress|ProcessSerialNumber\n|ProcessSerialNumberPtr|ProcHandle|Ptr|ResType|ResTypePtr|ShortFixed|ShortFixedPtr|SignedByte|SInt16|SInt32|SInt64\n|SInt8|Size|StrFileName|StringHandle|StringPtr|TimeBase|TimeRecord|TimeScale|TimeValue|TimeValue64|UInt16|UInt32\n|UInt64|UInt8|UniChar|UniCharCount|UniCharCountPtr|UniCharPtr|UnicodeScalarValue|UniversalProcHandle|UniversalProcPtr\n|UnsignedFixed|UnsignedFixedPtr|UnsignedWide|UTF16Char|UTF32Char|UTF8Char)\n\\b", + "name": "support.type.mac-classic.c" + }, + "anon_pattern_13": { + "match": "\\b([A-Za-z0-9_]+_t)\\b", + "name": "support.type.posix-reserved.c" + }, + "anon_pattern_14": { + "match": ";", + "name": "punctuation.terminator.statement.c" + }, + "anon_pattern_15": { + "match": ",", + "name": "punctuation.separator.delimiter.c" + }, + "anon_pattern_2": { + "match": "typedef", + "name": "keyword.other.typedef.c" + }, + "anon_pattern_3": { + "match": "\\b(const|extern|register|restrict|static|volatile|inline)\\b", + "name": "storage.modifier.c" + }, + "anon_pattern_4": { + "match": "\\bk[A-Z]\\w*\\b", + "name": "constant.other.variable.mac-classic.c" + }, + "anon_pattern_5": { + "match": "\\bg[A-Z]\\w*\\b", + "name": "variable.other.readwrite.global.mac-classic.c" + }, + "anon_pattern_6": { + "match": "\\bs[A-Z]\\w*\\b", + "name": "variable.other.readwrite.static.mac-classic.c" + }, + "anon_pattern_7": { + "match": "\\b(NULL|true|false|TRUE|FALSE)\\b", + "name": "constant.language.c" + }, + "anon_pattern_8": { + "match": "\\b(u_char|u_short|u_int|u_long|ushort|uint|u_quad_t|quad_t|qaddr_t|caddr_t|daddr_t|div_t|dev_t|fixpt_t|blkcnt_t|blksize_t|gid_t|in_addr_t|in_port_t|ino_t|key_t|mode_t|nlink_t|id_t|pid_t|off_t|segsz_t|swblk_t|uid_t|id_t|clock_t|size_t|ssize_t|time_t|useconds_t|suseconds_t)\\b", + "name": "support.type.sys-types.c" + }, + "anon_pattern_9": { + "match": "\\b(pthread_attr_t|pthread_cond_t|pthread_condattr_t|pthread_mutex_t|pthread_mutexattr_t|pthread_once_t|pthread_rwlock_t|pthread_rwlockattr_t|pthread_t|pthread_key_t)\\b", + "name": "support.type.pthread.c" + }, + "anon_pattern_range_1": { "name": "meta.preprocessor.macro.c", "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((#)\\s*define\\b)\\s+((?))((?:(?:[a-zA-Z_][a-zA-Z_0-9]*)\\s*(?:(?:\\.)|(?:->)))*)\\s*([a-zA-Z_][a-zA-Z_0-9]*)(\\()", - "beginCaptures": { - "1": { - "name": "variable.object.c" - }, - "2": { - "name": "punctuation.separator.dot-access.c" - }, - "3": { - "name": "punctuation.separator.pointer-access.c" - }, - "4": { - "patterns": [ - { - "match": "\\.", - "name": "punctuation.separator.dot-access.c" - }, - { - "match": "->", - "name": "punctuation.separator.pointer-access.c" - }, - { - "match": "[a-zA-Z_][a-zA-Z_0-9]*", - "name": "variable.object.c" - }, - { - "name": "everything.else.c", - "match": ".+" - } - ] - }, - "5": { - "name": "entity.name.function.member.c" - }, - "6": { - "name": "punctuation.section.arguments.begin.bracket.round.function.member.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.arguments.end.bracket.round.function.member.c" - } - }, - "patterns": [ - { - "include": "#function-call-innards" - } - ] - }, "backslash_escapes": { "match": "(?x)\\\\ (\n\\\\\t\t\t |\n[abefnprtv'\"?] |\n[0-3][0-7]{,2}\t |\n[4-7]\\d?\t\t|\nx[a-fA-F0-9]{,2} |\nu[a-fA-F0-9]{,4} |\nU[a-fA-F0-9]{,8} )", "name": "constant.character.escape.c" @@ -491,6 +563,40 @@ } ] }, + "block_comment": { + "patterns": [ + { + "begin": "\\s*+(\\/\\*)", + "end": "\\*\\/", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.c" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.c" + } + }, + "name": "comment.block.c" + }, + { + "begin": "\\s*+(\\/\\*)", + "end": "\\*\\/", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.c" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.c" + } + }, + "name": "comment.block.c" + } + ] + }, "block_innards": { "patterns": [ { @@ -557,7 +663,7 @@ "include": "#parens-block" }, { - "include": "$base" + "include": "$self" } ] }, @@ -632,339 +738,359 @@ "comments": { "patterns": [ { - "name": "comment.line.double-slash.documentation.c", - "begin": "(?:^)(?>\\s*)(\\/\\/[!\\/]+)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.documentation.c" - } - }, - "end": "(?<=\\n)(?|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.italic.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.bold.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.inline.raw.string.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { + "patterns": [ + { + "name": "comment.line.double-slash.documentation.c", + "begin": "(?:^)(?>\\s*)(\\/\\/[!\\/]+)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.documentation.c" + } + }, + "end": "(?<=\\n)(?|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.italic.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.bold.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.inline.raw.string.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "patterns": [ + { + "match": "in|out", + "name": "keyword.other.parameter.direction.$0.c" + } + ] + }, + "3": { + "name": "variable.parameter.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc" } ] }, - "3": { - "name": "variable.parameter.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc" - } - ] - }, - { - "match": "(\\/\\*[!*]+(?=\\s))(.+)([!*]*\\*\\/)", - "captures": { - "1": { - "name": "punctuation.definition.comment.begin.documentation.c" - }, - "2": { - "patterns": [ { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "match": "(\\/\\*[!*]+(?=\\s))(.+)([!*]*\\*\\/)", "captures": { "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.italic.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.bold.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.inline.raw.string.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" + "name": "punctuation.definition.comment.begin.documentation.c" }, "2": { "patterns": [ { - "match": "in|out", - "name": "keyword.other.parameter.direction.$0.c" + "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.italic.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.bold.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.inline.raw.string.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "patterns": [ + { + "match": "in|out", + "name": "keyword.other.parameter.direction.$0.c" + } + ] + }, + "3": { + "name": "variable.parameter.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc" } ] }, "3": { - "name": "variable.parameter.c" + "name": "punctuation.definition.comment.end.documentation.c" + } + }, + "name": "comment.block.documentation.c" + }, + { + "name": "comment.block.documentation.c", + "begin": "((?>\\s*)\\/\\*[!*]+(?:(?:\\n|$)|(?=\\s)))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.documentation.c" + } + }, + "end": "([!*]*\\*\\/)", + "endCaptures": { + "1": { + "name": "punctuation.definition.comment.end.documentation.c" + } + }, + "patterns": [ + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.italic.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.bold.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.inline.raw.string.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "patterns": [ + { + "match": "in|out", + "name": "keyword.other.parameter.direction.$0.c" + } + ] + }, + "3": { + "name": "variable.parameter.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc" + } + ] + }, + { + "match": "^\\/\\* =(\\s*.*?)\\s*= \\*\\/$\\n?", + "captures": { + "1": { + "name": "meta.toc-list.banner.block.c" + } + }, + "name": "comment.block.banner.c" + }, + { + "name": "comment.block.c", + "begin": "(\\/\\*)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.c" + } + }, + "end": "(\\*\\/)", + "endCaptures": { + "1": { + "name": "punctuation.definition.comment.end.c" } } }, { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" + "match": "^\\/\\/ =(\\s*.*?)\\s*=$\\n?", + "captures": { + "1": { + "name": "meta.toc-list.banner.line.c" + } + }, + "name": "comment.line.banner.c" }, { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc" - } - ] - }, - "3": { - "name": "punctuation.definition.comment.end.documentation.c" - } - }, - "name": "comment.block.documentation.c" - }, - { - "name": "comment.block.documentation.c", - "begin": "((?>\\s*)\\/\\*[!*]+(?:(?:\\n|$)|(?=\\s)))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.begin.documentation.c" - } - }, - "end": "([!*]*\\*\\/)", - "endCaptures": { - "1": { - "name": "punctuation.definition.comment.end.documentation.c" - } - }, - "patterns": [ - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.italic.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.bold.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.inline.raw.string.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { + "begin": "((?:^[ \\t]+)?)(?=\\/\\/)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.c" + } + }, + "end": "(?!\\G)", "patterns": [ { - "match": "in|out", - "name": "keyword.other.parameter.direction.$0.c" + "name": "comment.line.double-slash.c", + "begin": "(\\/\\/)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.c" + } + }, + "end": "(?=\\n)", + "patterns": [ + { + "include": "#line_continuation_character" + } + ] } ] - }, - "3": { - "name": "variable.parameter.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc" - } - ] - }, - { - "match": "^\\/\\* =(\\s*.*?)\\s*= \\*\\/$\\n?", - "captures": { - "1": { - "name": "meta.toc-list.banner.block.c" - } - }, - "name": "comment.block.banner.c" - }, - { - "name": "comment.block.c", - "begin": "(\\/\\*)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.begin.c" - } - }, - "end": "(\\*\\/)", - "endCaptures": { - "1": { - "name": "punctuation.definition.comment.end.c" - } - } - }, - { - "match": "^\\/\\/ =(\\s*.*?)\\s*=$\\n?", - "captures": { - "1": { - "name": "meta.toc-list.banner.line.c" - } - }, - "name": "comment.line.banner.c" - }, - { - "begin": "((?:^[ \\t]+)?)(?=\\/\\/)", - "beginCaptures": { - "1": { - "name": "punctuation.whitespace.comment.leading.c" - } - }, - "end": "(?!\\G)", - "patterns": [ - { - "name": "comment.line.double-slash.c", - "begin": "(\\/\\/)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.c" - } - }, - "end": "(?=\\n)", - "patterns": [ - { - "include": "#line_continuation_character" } ] + }, + { + "include": "#block_comment" + }, + { + "include": "#line_comment" } ] + }, + { + "include": "#block_comment" + }, + { + "include": "#line_comment" } ] }, @@ -1034,7 +1160,7 @@ "include": "#function-call-innards" }, { - "include": "$base" + "include": "$self" } ] }, @@ -1161,32 +1287,122 @@ ] }, { - "include": "$base" + "include": "$self" } ] }, "inline_comment": { - "match": "(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", - "captures": { - "1": { - "name": "comment.block.c punctuation.definition.comment.begin.c" - }, - "2": { - "name": "comment.block.c" - }, - "3": { + "patterns": [ + { "patterns": [ { - "match": "\\*\\/", - "name": "comment.block.c punctuation.definition.comment.end.c" + "match": "(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", + "captures": { + "1": { + "name": "comment.block.c punctuation.definition.comment.begin.c" + }, + "2": { + "name": "comment.block.c" + }, + "3": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.c punctuation.definition.comment.end.c" + }, + { + "match": "\\*", + "name": "comment.block.c" + } + ] + } + } }, { - "match": "\\*", + "match": "(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/))", + "captures": { + "1": { + "name": "comment.block.c punctuation.definition.comment.begin.c" + }, + "2": { + "name": "comment.block.c" + }, + "3": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.c punctuation.definition.comment.end.c" + }, + { + "match": "\\*", + "name": "comment.block.c" + } + ] + } + } + } + ] + }, + { + "match": "(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/))", + "captures": { + "1": { + "name": "comment.block.c punctuation.definition.comment.begin.c" + }, + "2": { "name": "comment.block.c" + }, + "3": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.c punctuation.definition.comment.end.c" + }, + { + "match": "\\*", + "name": "comment.block.c" + } + ] + } + } + } + ] + }, + "line_comment": { + "patterns": [ + { + "begin": "\\s*+(\\/\\/)", + "end": "(?<=\\n)(?(?:\\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)))((?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\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|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)))(?=\\())", "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<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|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)))(\\{)", "end": "\\}|(?=(?(?:\\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))))*)(~(?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\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|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)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\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|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)+)?((?|\\?\\?>)(?:(?:\\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|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)*+)?(\\()", "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|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|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)))(?=\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))", + "match": "((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))", "captures": { "1": { "name": "storage.modifier.$1.cpp" @@ -3998,7 +3992,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|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<:.]))", "captures": { "1": { "name": "punctuation.definition.function.return-type.cpp" @@ -4246,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|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|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)+)?(\\()", "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|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|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)+)?(\\()", "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|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|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<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -5340,15 +5334,23 @@ "name": "storage.modifier.lambda.$0.cpp" }, { - "match": "(->)((?:.+?(?=\\{|$))?)", - "captures": { - "1": { + "begin": "->", + "end": "(?=\\{)|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(#)(?:(?:\\s)+)?line\\b", - "end": "(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(#)(?:(?:\\s)+)?define\\b)(?:(?:\\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|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)))(?=\\<|\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "source.cpp#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.function.cpp" + }, + "7": { + "name": "keyword.other.delete.function.cpp" + } + } + }, { "include": "$self" } @@ -6912,14 +6954,14 @@ }, { "match": "&|\\||\\^|~", - "name": "keyword.operator.cpp" + "name": "keyword.operator.bitwise.cpp" }, { "include": "source.cpp#assignment_operator" }, { "match": "%|\\*|\\/|-|\\+", - "name": "keyword.operator.cpp" + "name": "keyword.operator.arithmetic.cpp" }, { "include": "#ternary_operator" @@ -6976,7 +7018,7 @@ "include": "source.cpp#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": [ @@ -7356,7 +7398,7 @@ "include": "source.cpp#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": [ @@ -7708,7 +7750,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<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|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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()|(?=(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\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)))((?|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -1653,10 +1650,10 @@ ] }, "6": { - "name": "keyword.other.default.constructor.cpp" + "name": "keyword.other.default.function.cpp keyword.other.default.constructor.cpp" }, "7": { - "name": "keyword.other.delete.constructor.cpp" + "name": "keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp" } } }, @@ -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|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)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -2028,10 +2025,10 @@ ] }, "6": { - "name": "keyword.other.default.constructor.cpp" + "name": "keyword.other.default.function.cpp keyword.other.default.constructor.cpp" }, "7": { - "name": "keyword.other.delete.constructor.cpp" + "name": "keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp" } } }, @@ -2285,7 +2282,7 @@ ] }, "curly_initializer": { - "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)))(\\{)", + "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)))(\\{)", "end": "\\}", "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))))*)(~(?|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -3302,10 +3296,10 @@ ] }, "6": { - "name": "keyword.other.default.constructor.cpp" + "name": "keyword.other.default.function.cpp keyword.other.default.constructor.cpp keyword.other.default.destructor.cpp" }, "7": { - "name": "keyword.other.delete.constructor.cpp" + "name": "keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp keyword.other.delete.destructor.cpp" } } }, @@ -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|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)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -3593,10 +3587,10 @@ ] }, "6": { - "name": "keyword.other.default.constructor.cpp" + "name": "keyword.other.default.function.cpp keyword.other.default.constructor.cpp keyword.other.default.destructor.cpp" }, "7": { - "name": "keyword.other.delete.constructor.cpp" + "name": "keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp keyword.other.delete.destructor.cpp" } } }, @@ -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|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)+)?((?|\\?\\?>)(?:(?:\\s)+)?(;)|(;))|(?=[;>\\[\\]=]))", "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|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)*+)?(\\()", "end": "\\)", "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|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)))(?=\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "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|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<:.]))", "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|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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "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|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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "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|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<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -6916,15 +6944,23 @@ "name": "storage.modifier.lambda.$0.cpp" }, { - "match": "(->)((?:.+?(?=\\{|$))?)", - "captures": { - "1": { + "begin": "->", + "end": "(?=\\{)", + "beginCaptures": { + "0": { "name": "punctuation.definition.lambda.return-type.cpp" + } + }, + "endCaptures": {}, + "patterns": [ + { + "include": "#comments" }, - "2": { + { + "match": "\\S+", "name": "storage.type.return-type.lambda.cpp" } - } + ] }, { "begin": "\\{", @@ -6954,7 +6990,7 @@ }, "line": { "begin": "^((?:(?:(?:(?>(?:\\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_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(?!\\())", "captures": { "1": { "patterns": [ @@ -7474,7 +7511,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|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)))(?=\\<|\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -8707,6 +8744,45 @@ { "include": "#qualifiers_and_specifiers_post_parameters" }, + { + "match": "(\\=)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.function.cpp" + }, + "7": { + "name": "keyword.other.delete.function.cpp" + } + } + }, { "include": "$self" } @@ -9062,14 +9138,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 +9155,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 +9484,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 +9813,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 +10142,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 +10522,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 +10844,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 +11173,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 +11560,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 +11884,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 +12213,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 +12570,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|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<:.])", "captures": { "0": { "patterns": [ @@ -13013,27 +13089,27 @@ "name": "meta.qualified_type.cpp" }, "qualifiers_and_specifiers_post_parameters": { - "match": "((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))", + "match": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\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" - } - ] + "5": { + "name": "storage.modifier.specifier.functional.post-parameters.$5.cpp" } } } @@ -13089,7 +13131,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|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*+", "captures": { "0": { "patterns": [ @@ -13111,7 +13153,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|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*+", "captures": { "0": { "patterns": [ @@ -13133,7 +13175,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13171,7 +13213,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|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*+", "captures": { "0": { "patterns": [ @@ -13193,7 +13235,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13231,7 +13273,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|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*+", "captures": { "0": { "patterns": [ @@ -13253,7 +13295,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13291,7 +13333,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13329,7 +13371,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|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*+", "captures": { "0": { "patterns": [ @@ -13351,7 +13393,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13389,7 +13431,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|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*+", "captures": { "0": { "patterns": [ @@ -13411,7 +13453,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13449,7 +13491,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|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*+", "captures": { "0": { "patterns": [ @@ -13471,7 +13513,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13509,7 +13551,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|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*+", "captures": { "0": { "patterns": [ @@ -13531,7 +13573,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13569,7 +13611,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|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*+", "captures": { "0": { "patterns": [ @@ -13591,7 +13633,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13629,7 +13671,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|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*+", "captures": { "0": { "patterns": [ @@ -13651,7 +13693,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|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)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13693,7 +13735,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|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))))*(?:&|(?:\\*)))?", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -15207,7 +15249,7 @@ } }, "storage_specifiers": { - "match": "((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\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}))*)|((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:\\s)+)+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))|((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)(?:(?:\\s)+)?(\\.\\.\\.)(?:(?:\\s)+)?((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))(?:(?:\\s)+)?(?:(,)|(?=>|$))", + "match": "((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)|((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:\\s)+)+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))|((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)(?:(?:\\s)+)?(\\.\\.\\.)(?:(?:\\s)+)?((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))|(?)(?:(?:\\s)+)?(class|typename)(?:(?:\\s)+((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))?)(?:(?:\\s)+)?(?:(\\=)(?:(?:\\s)+)?(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-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": { "patterns": [ @@ -16311,7 +16347,7 @@ "name": "entity.name.type.template.cpp" }, "6": { - "name": "storage.type.template.cpp" + "name": "storage.type.template.argument.$6.cpp" }, "7": { "name": "punctuation.vararg-ellipses.template.definition.cpp" @@ -16320,6 +16356,30 @@ "name": "entity.name.type.template.cpp" }, "9": { + "name": "storage.type.template.cpp" + }, + "10": { + "name": "punctuation.section.angle-brackets.begin.template.definition.cpp" + }, + "11": { + "name": "storage.type.template.argument.$11.cpp" + }, + "12": { + "name": "entity.name.type.template.cpp" + }, + "13": { + "name": "punctuation.section.angle-brackets.end.template.definition.cpp" + }, + "14": { + "name": "storage.type.template.argument.$14.cpp" + }, + "15": { + "name": "entity.name.type.template.cpp" + }, + "16": { + "name": "keyword.operator.assignment.cpp" + }, + "17": { "name": "punctuation.separator.delimiter.comma.template.argument.cpp" } } @@ -16344,13 +16404,13 @@ ] }, "template_isolated_definition": { - "match": "(?(?:(?:\\s)+)?$)", + "match": "(?)(?:(?:\\s)+)?$", "captures": { "1": { "name": "storage.type.template.cpp" }, "2": { - "name": "punctuation.section.angle-brackets.start.template.definition.cpp" + "name": "punctuation.section.angle-brackets.begin.template.definition.cpp" }, "3": { "name": "meta.template.definition.cpp", @@ -16503,7 +16563,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|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|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)", "captures": { "1": { "name": "keyword.other.using.directive.cpp" @@ -17593,7 +17653,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|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)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "beginCaptures": { "1": { @@ -18878,7 +18938,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|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<:.]))", "captures": { "1": { "name": "storage.modifier.cpp" @@ -19767,7 +19827,7 @@ } }, "using_namespace": { - "begin": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((? ({ languageId, settingId: `${languageId}.format.enable`, provider: undefined })); // Options to control the language client - let clientOptions: LanguageClientOptions = { + const clientOptions: LanguageClientOptions = { documentSelector, synchronize: { configurationSection: ['css', 'scss', 'less'] @@ -98,7 +98,7 @@ export async function startClient(context: ExtensionContext, newLanguageClient: }; // Create the language client and start the client. - let client = newLanguageClient('css', localize('cssserver.name', 'CSS Language Server'), clientOptions); + const client = newLanguageClient('css', localize('cssserver.name', 'CSS Language Server'), clientOptions); client.registerProposedFeatures(); await client.start(); @@ -125,17 +125,17 @@ export async function startClient(context: ExtensionContext, newLanguageClient: return languages.registerCompletionItemProvider(documentSelector, { provideCompletionItems(doc: TextDocument, pos: Position) { - let lineUntilPos = doc.getText(new Range(new Position(pos.line, 0), pos)); - let match = lineUntilPos.match(regionCompletionRegExpr); + const lineUntilPos = doc.getText(new Range(new Position(pos.line, 0), pos)); + const match = lineUntilPos.match(regionCompletionRegExpr); if (match) { - let range = new Range(new Position(pos.line, match[1].length), pos); - let beginProposal = new CompletionItem('#region', CompletionItemKind.Snippet); + const range = new Range(new Position(pos.line, match[1].length), pos); + const beginProposal = new CompletionItem('#region', CompletionItemKind.Snippet); beginProposal.range = range; TextEdit.replace(range, '/* #region */'); beginProposal.insertText = new SnippetString('/* #region $1*/'); beginProposal.documentation = localize('folding.start', 'Folding Region Start'); beginProposal.filterText = match[2]; beginProposal.sortText = 'za'; - let endProposal = new CompletionItem('#endregion', CompletionItemKind.Snippet); + const endProposal = new CompletionItem('#endregion', CompletionItemKind.Snippet); endProposal.range = range; endProposal.insertText = '/* #endregion */'; endProposal.documentation = localize('folding.end', 'Folding Region End'); @@ -151,13 +151,13 @@ export async function startClient(context: ExtensionContext, newLanguageClient: commands.registerCommand('_css.applyCodeAction', applyCodeAction); function applyCodeAction(uri: string, documentVersion: number, edits: TextEdit[]) { - let textEditor = window.activeTextEditor; + const textEditor = window.activeTextEditor; if (textEditor && textEditor.document.uri.toString() === uri) { if (textEditor.document.version !== documentVersion) { window.showInformationMessage(`CSS fix is outdated and can't be applied to the document.`); } textEditor.edit(mutator => { - for (let edit of edits) { + for (const edit of edits) { mutator.replace(client.protocol2CodeConverter.asRange(edit.range), edit.newText); } }).then(success => { diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index ccf0518633f..497f6cd735c 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -994,9 +994,9 @@ ] }, "dependencies": { - "vscode-languageclient": "^8.0.2-next.4", - "vscode-nls": "^5.0.0", - "vscode-uri": "^3.0.3" + "vscode-languageclient": "^8.1.0-next.1", + "vscode-nls": "^5.2.0", + "vscode-uri": "^3.0.6" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index 0885f1b1d07..2528682c661 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -10,9 +10,9 @@ "main": "./out/node/cssServerMain", "browser": "./dist/browser/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^6.0.1", - "vscode-languageserver": "^8.0.2-next.4", - "vscode-uri": "^3.0.3" + "vscode-css-languageservice": "^6.1.1", + "vscode-languageserver": "^8.1.0-next.1", + "vscode-uri": "^3.0.6" }, "devDependencies": { "@types/mocha": "^9.1.1", diff --git a/extensions/css-language-features/server/src/cssServer.ts b/extensions/css-language-features/server/src/cssServer.ts index 314aa8aebc0..c5db57340fd 100644 --- a/extensions/css-language-features/server/src/cssServer.ts +++ b/extensions/css-language-features/server/src/cssServer.ts @@ -7,7 +7,7 @@ import { Connection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, ConfigurationRequest, WorkspaceFolder, TextDocumentSyncKind, NotificationType, Disposable, TextDocumentIdentifier, Range, FormattingOptions, TextEdit, Diagnostic } from 'vscode-languageserver'; import { URI } from 'vscode-uri'; -import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet, TextDocument, Position, CSSFormatConfiguration } from 'vscode-css-languageservice'; +import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet, TextDocument, Position } from 'vscode-css-languageservice'; import { getLanguageModelCache } from './languageModelCache'; import { runSafeAsync } from './utils/runner'; import { DiagnosticsSupport, registerDiagnosticsPullSupport, registerDiagnosticsPushSupport } from './utils/validation'; @@ -74,7 +74,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) if (!Array.isArray(workspaceFolders)) { workspaceFolders = []; if (params.rootPath) { - workspaceFolders.push({ name: '', uri: URI.file(params.rootPath).toString() }); + workspaceFolders.push({ name: '', uri: URI.file(params.rootPath).toString(true) }); } } @@ -223,7 +223,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) if (document) { await dataProvidersReady; const stylesheet = stylesheets.get(document); - return getLanguageService(document).findDocumentSymbols(document, stylesheet); + return getLanguageService(document).findDocumentSymbols2(document, stylesheet); } return []; }, [], `Error while computing document symbols for ${documentSymbolParams.textDocument.uri}`, token); @@ -356,8 +356,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) async function onFormat(textDocument: TextDocumentIdentifier, range: Range | undefined, options: FormattingOptions): Promise { const document = documents.get(textDocument.uri); if (document) { - console.log(JSON.stringify(options)); - const edits = getLanguageService(document).format(document, range ?? getFullRange(document), options as CSSFormatConfiguration); + const edits = getLanguageService(document).format(document, range ?? getFullRange(document), options); if (edits.length > formatterMaxNumberOfEdits) { const newText = TextDocument.applyEdits(document, edits); return [TextEdit.replace(getFullRange(document), newText)]; diff --git a/extensions/css-language-features/server/src/languageModelCache.ts b/extensions/css-language-features/server/src/languageModelCache.ts index 343d57a9ad6..f39eada6f44 100644 --- a/extensions/css-language-features/server/src/languageModelCache.ts +++ b/extensions/css-language-features/server/src/languageModelCache.ts @@ -18,10 +18,10 @@ export function getLanguageModelCache(maxEntries: number, cleanupIntervalTime let cleanupInterval: NodeJS.Timer | undefined = undefined; if (cleanupIntervalTimeInSec > 0) { cleanupInterval = setInterval(() => { - let cutoffTime = Date.now() - cleanupIntervalTimeInSec * 1000; - let uris = Object.keys(languageModels); - for (let uri of uris) { - let languageModelInfo = languageModels[uri]; + const cutoffTime = Date.now() - cleanupIntervalTimeInSec * 1000; + const uris = Object.keys(languageModels); + for (const uri of uris) { + const languageModelInfo = languageModels[uri]; if (languageModelInfo.cTime < cutoffTime) { delete languageModels[uri]; nModels--; @@ -32,14 +32,14 @@ export function getLanguageModelCache(maxEntries: number, cleanupIntervalTime return { get(document: TextDocument): T { - let version = document.version; - let languageId = document.languageId; - let languageModelInfo = languageModels[document.uri]; + const version = document.version; + const languageId = document.languageId; + const languageModelInfo = languageModels[document.uri]; if (languageModelInfo && languageModelInfo.version === version && languageModelInfo.languageId === languageId) { languageModelInfo.cTime = Date.now(); return languageModelInfo.languageModel; } - let languageModel = parse(document); + const languageModel = parse(document); languageModels[document.uri] = { languageModel, version, languageId, cTime: Date.now() }; if (!languageModelInfo) { nModels++; @@ -48,8 +48,8 @@ export function getLanguageModelCache(maxEntries: number, cleanupIntervalTime if (nModels === maxEntries) { let oldestTime = Number.MAX_VALUE; let oldestUri = null; - for (let uri in languageModels) { - let languageModelInfo = languageModels[uri]; + for (const uri in languageModels) { + const languageModelInfo = languageModels[uri]; if (languageModelInfo.cTime < oldestTime) { oldestUri = uri; oldestTime = languageModelInfo.cTime; @@ -64,7 +64,7 @@ export function getLanguageModelCache(maxEntries: number, cleanupIntervalTime }, onDocumentRemoved(document: TextDocument) { - let uri = document.uri; + const uri = document.uri; if (languageModels[uri]) { delete languageModels[uri]; nModels--; diff --git a/extensions/css-language-features/server/src/requests.ts b/extensions/css-language-features/server/src/requests.ts index 0726af35c56..3d21e542362 100644 --- a/extensions/css-language-features/server/src/requests.ts +++ b/extensions/css-language-features/server/src/requests.ts @@ -65,7 +65,7 @@ export interface RequestService { export function getRequestService(handledSchemas: string[], connection: Connection, runtime: RuntimeEnvironment): RequestService { const builtInHandlers: { [protocol: string]: RequestService | undefined } = {}; - for (let protocol of handledSchemas) { + for (const protocol of handledSchemas) { if (protocol === 'file') { builtInHandlers[protocol] = runtime.file; } else if (protocol === 'http' || protocol === 'https') { diff --git a/extensions/css-language-features/server/src/test/completion.test.ts b/extensions/css-language-features/server/src/test/completion.test.ts index 6881dd0e3e3..efb2953e3ec 100644 --- a/extensions/css-language-features/server/src/test/completion.test.ts +++ b/extensions/css-language-features/server/src/test/completion.test.ts @@ -19,13 +19,13 @@ export interface ItemDescription { suite('Completions', () => { - let assertCompletion = function (completions: CompletionList, expected: ItemDescription, document: TextDocument, _offset: number) { - let matches = completions.items.filter(completion => { + const assertCompletion = function (completions: CompletionList, expected: ItemDescription, document: TextDocument, _offset: number) { + const matches = completions.items.filter(completion => { return completion.label === expected.label; }); assert.strictEqual(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`); - let match = matches[0]; + const match = matches[0]; if (expected.resultText && TextEdit.is(match.textEdit)) { assert.strictEqual(TextDocument.applyEdits(document, [match.textEdit]), expected.resultText); } @@ -47,21 +47,21 @@ suite('Completions', () => { const context = getDocumentContext(testUri, workspaceFolders); const stylesheet = cssLanguageService.parseStylesheet(document); - let list = await cssLanguageService.doComplete2(document, position, stylesheet, context); + const list = await cssLanguageService.doComplete2(document, position, stylesheet, context); if (expected.count) { assert.strictEqual(list.items.length, expected.count); } if (expected.items) { - for (let item of expected.items) { + for (const item of expected.items) { assertCompletion(list, item, document, offset); } } } test('CSS url() Path completion', async function () { - let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + 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 () { - let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + 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 () { - let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + 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 () { - let testCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + 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); - let 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 () { - let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; + 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 bc4c6db6477..f6b1a349c70 100644 --- a/extensions/css-language-features/server/src/test/links.test.ts +++ b/extensions/css-language-features/server/src/test/links.test.ts @@ -21,13 +21,13 @@ export interface ItemDescription { suite('Links', () => { const cssLanguageService = getCSSLanguageService({ fileSystemProvider: getNodeFSRequestService() }); - let assertLink = function (links: DocumentLink[], expected: ItemDescription, document: TextDocument) { - let matches = links.filter(link => { + const assertLink = function (links: DocumentLink[], expected: ItemDescription, document: TextDocument) { + const matches = links.filter(link => { return document.offsetAt(link.range.start) === expected.offset; }); assert.strictEqual(matches.length, 1, `${expected.offset} should only existing once: Actual: ${links.map(l => document.offsetAt(l.range.start)).join(', ')}`); - let match = matches[0]; + const match = matches[0]; assert.strictEqual(document.getText(match.range), expected.value); assert.strictEqual(match.target, expected.target); }; @@ -45,33 +45,43 @@ suite('Links', () => { const context = getDocumentContext(testUri, workspaceFolders); const stylesheet = cssLanguageService.parseStylesheet(document); - let links = await cssLanguageService.findDocumentLinks2(document, stylesheet, context)!; + const links = await cssLanguageService.findDocumentLinks2(document, stylesheet, context)!; assert.strictEqual(links.length, expected.length); - for (let item of expected) { + for (const item of expected) { assertLink(links, item, document); } } 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 () { - let testUri = getTestResource('about.css'); - let folders = [{ name: 'x', uri: getTestResource('') }]; + const testUri = getTestResource('about.css'); + const folders = [{ name: 'x', uri: getTestResource('') }]; await assertLinks('html { background-image: url("hello.html|")', [{ offset: 29, value: '"hello.html"', target: getTestResource('hello.html') }], testUri, folders ); }); + test('url links - untitled', async function () { + + const testUri = 'untitled:untitled-1'; + const folders = [{ name: 'x', uri: getTestResource('') }]; + + await assertLinks('@import url("base.css|");")', + [{ offset: 12, value: '"base.css"', target: 'untitled:base.css' }], testUri, folders + ); + }); + test('node module resolving', async function () { - let testUri = getTestResource('about.css'); - let folders = [{ name: 'x', uri: getTestResource('') }]; + const testUri = getTestResource('about.css'); + const folders = [{ name: 'x', uri: getTestResource('') }]; await assertLinks('html { background-image: url("~foo/hello.html|")', [{ offset: 29, value: '"~foo/hello.html"', target: getTestResource('node_modules/foo/hello.html') }], testUri, folders @@ -80,8 +90,8 @@ suite('Links', () => { test('node module subfolder resolving', async function () { - let testUri = getTestResource('subdir/about.css'); - let folders = [{ name: 'x', uri: getTestResource('') }]; + const testUri = getTestResource('subdir/about.css'); + const folders = [{ name: 'x', uri: getTestResource('') }]; await assertLinks('html { background-image: url("~foo/hello.html|")', [{ offset: 29, value: '"~foo/hello.html"', target: getTestResource('node_modules/foo/hello.html') }], testUri, folders diff --git a/extensions/css-language-features/server/src/utils/documentContext.ts b/extensions/css-language-features/server/src/utils/documentContext.ts index a7beffd0310..c9f46fb7578 100644 --- a/extensions/css-language-features/server/src/utils/documentContext.ts +++ b/extensions/css-language-features/server/src/utils/documentContext.ts @@ -10,7 +10,7 @@ import { Utils, URI } from 'vscode-uri'; export function getDocumentContext(documentUri: string, workspaceFolders: WorkspaceFolder[]): DocumentContext { function getRootFolder(): string | undefined { - for (let folder of workspaceFolders) { + for (const folder of workspaceFolders) { let folderURI = folder.uri; if (!endsWith(folderURI, '/')) { folderURI = folderURI + '/'; @@ -25,13 +25,14 @@ export function getDocumentContext(documentUri: string, workspaceFolders: Worksp return { resolveReference: (ref: string, base = documentUri) => { if (ref[0] === '/') { // resolve absolute path against the current workspace folder - let folderUri = getRootFolder(); + 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(); + const baseUri = URI.parse(base); + const baseUriDir = baseUri.path.endsWith('/') ? baseUri : Utils.dirname(baseUri); + return Utils.resolvePath(baseUriDir, ref).toString(true); }, }; } diff --git a/extensions/css-language-features/server/src/utils/runner.ts b/extensions/css-language-features/server/src/utils/runner.ts index 47c587537aa..383b88e4487 100644 --- a/extensions/css-language-features/server/src/utils/runner.ts +++ b/extensions/css-language-features/server/src/utils/runner.ts @@ -8,7 +8,7 @@ import { RuntimeEnvironment } from '../cssServer'; export function formatError(message: string, err: any): string { if (err instanceof Error) { - let error = err; + const error = err; return `${message}: ${error.message}\n${error.stack}`; } else if (typeof err === 'string') { return `${message}: ${err}`; diff --git a/extensions/css-language-features/server/src/utils/strings.ts b/extensions/css-language-features/server/src/utils/strings.ts index 0e9ed34f83d..1e53c4204fd 100644 --- a/extensions/css-language-features/server/src/utils/strings.ts +++ b/extensions/css-language-features/server/src/utils/strings.ts @@ -21,7 +21,7 @@ export function startsWith(haystack: string, needle: string): boolean { * Determines if haystack ends with needle. */ export function endsWith(haystack: string, needle: string): boolean { - let diff = haystack.length - needle.length; + const diff = haystack.length - needle.length; if (diff > 0) { return haystack.lastIndexOf(needle) === diff; } else if (diff === 0) { diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index 9a9938963fd..ec35ce87045 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -12,57 +12,52 @@ 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.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.1.1.tgz#36daefd96e56b7453da16ff8c16f4ee693f32521" + integrity sha512-7d2NCq2plT0njAKmGZ11uof95y2fwbgq8QuToE3kX9uYQfVmejHX2/lFGKbK5AV5+Ja0L80UZoU0QspwqMKMHA== dependencies: - vscode-languageserver-textdocument "^1.0.4" - vscode-languageserver-types "^3.17.1" - vscode-nls "^5.0.1" - vscode-uri "^3.0.3" + vscode-languageserver-textdocument "^1.0.7" + vscode-languageserver-types "^3.17.2" + vscode-nls "^5.2.0" + vscode-uri "^3.0.4" -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" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" - integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== +vscode-uri@^3.0.6, vscode-uri@^3.0.4: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.6.tgz#5e6e2e1a4170543af30151b561a41f71db1d6f91" + integrity sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ== diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index 9b7854145e5..dc44620a06b 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,56 +26,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" -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" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" - integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== +vscode-uri@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.6.tgz#5e6e2e1a4170543af30151b561a41f71db1d6f91" + integrity sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ== yallist@^4.0.0: version "4.0.0" 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..87690afef24 100644 --- a/extensions/debug-auto-launch/package.json +++ b/extensions/debug-auto-launch/package.json @@ -16,7 +16,7 @@ } }, "activationEvents": [ - "*" + "onStartupFinished" ], "main": "./out/extension", "scripts": { @@ -33,7 +33,7 @@ ] }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/debug-auto-launch/src/extension.ts b/extensions/debug-auto-launch/src/extension.ts index a4a48f5c380..86de0ac6ea4 100644 --- a/extensions/debug-auto-launch/src/extension.ts +++ b/extensions/debug-auto-launch/src/extension.ts @@ -8,6 +8,12 @@ import { createServer, Server } from 'net'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; +const enum State { + Disabled = 'disabled', + OnlyWithFlag = 'onlyWithFlag', + Smart = 'smart', + Always = 'always', +} const localize = nls.loadMessageBundle(); const TEXT_STATUSBAR_LABEL = { [State.Disabled]: localize('status.text.auto.attach.disabled', 'Auto Attach: Disabled'), @@ -62,12 +68,6 @@ const SETTINGS_CAUSE_REFRESH = new Set( ['autoAttachSmartPattern', SETTING_STATE].map(s => `${SETTING_SECTION}.${s}`), ); -const enum State { - Disabled = 'disabled', - OnlyWithFlag = 'onlyWithFlag', - Smart = 'smart', - Always = 'always', -} let currentState: Promise<{ context: vscode.ExtensionContext; state: State | null }>; let statusItem: vscode.StatusBarItem | undefined; // and there is no status bar item @@ -243,7 +243,7 @@ const createServerInner = async (ipcAddress: string) => { const createServerInstance = (ipcAddress: string) => new Promise((resolve, reject) => { const s = createServer(socket => { - let data: Buffer[] = []; + const data: Buffer[] = []; socket.on('data', async chunk => { if (chunk[chunk.length - 1] !== 0) { // terminated with NUL byte @@ -392,7 +392,7 @@ async function getIpcAddress(context: vscode.ExtensionContext) { } function getJsDebugSettingKey() { - let o: { [key: string]: unknown } = {}; + const o: { [key: string]: unknown } = {}; const config = vscode.workspace.getConfiguration(SETTING_SECTION); for (const setting of SETTINGS_CAUSE_REFRESH) { o[setting] = config.get(setting); diff --git a/extensions/debug-auto-launch/yarn.lock b/extensions/debug-auto-launch/yarn.lock index 22c406bc73f..8b8c7a6c15b 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.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== diff --git a/extensions/debug-server-ready/package.json b/extensions/debug-server-ready/package.json index 29cee88c0c5..09cd096bff3 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.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/debug-server-ready/src/extension.ts b/extensions/debug-server-ready/src/extension.ts index d112651fd09..a3214e1207b 100644 --- a/extensions/debug-server-ready/src/extension.ts +++ b/extensions/debug-server-ready/src/extension.ts @@ -57,7 +57,7 @@ class ServerReadyDetector extends vscode.Disposable { } static stop(session: vscode.DebugSession): void { - let detector = ServerReadyDetector.detectors.get(session); + const detector = ServerReadyDetector.detectors.get(session); if (detector) { ServerReadyDetector.detectors.delete(session); detector.dispose(); @@ -65,7 +65,7 @@ class ServerReadyDetector extends vscode.Disposable { } static rememberShellPid(session: vscode.DebugSession, pid: number) { - let detector = ServerReadyDetector.detectors.get(session); + const detector = ServerReadyDetector.detectors.get(session); if (detector) { detector.shellPid = pid; } @@ -77,7 +77,7 @@ class ServerReadyDetector extends vscode.Disposable { // first find the detector with a matching pid const pid = await e.terminal.processId; - for (let [, detector] of this.detectors) { + for (const [, detector] of this.detectors) { if (detector.shellPid === pid) { detector.detectPattern(e.data); return; @@ -85,7 +85,7 @@ class ServerReadyDetector extends vscode.Disposable { } // if none found, try all detectors until one matches - for (let [, detector] of this.detectors) { + for (const [, detector] of this.detectors) { if (detector.detectPattern(e.data)) { return; } diff --git a/extensions/debug-server-ready/yarn.lock b/extensions/debug-server-ready/yarn.lock index 22c406bc73f..8b8c7a6c15b 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.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== diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 659be1e0fce..2ec3d79ce6f 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": { @@ -73,7 +74,6 @@ "type": "string" }, "default": {}, - "scope": "resource", "markdownDescription": "%emmetIncludeLanguages%" }, "emmet.variables": { @@ -92,13 +92,11 @@ "type": "string" }, "default": {}, - "scope": "resource", "markdownDescription": "%emmetVariables%" }, "emmet.syntaxProfiles": { "type": "object", "default": {}, - "scope": "resource", "markdownDescription": "%emmetSyntaxProfiles%" }, "emmet.excludeLanguages": { @@ -109,7 +107,6 @@ "default": [ "markdown" ], - "scope": "resource", "markdownDescription": "%emmetExclude%" }, "emmet.extensionsPath": { @@ -125,12 +122,17 @@ "emmet.triggerExpansionOnTab": { "type": "boolean", "default": false, + "scope": "language-overridable", "markdownDescription": "%emmetTriggerExpansionOnTab%" }, + "emmet.useInlineCompletions": { + "type": "boolean", + "default": false, + "markdownDescription": "%emmetUseInlineCompletions%" + }, "emmet.preferences": { "type": "object", "default": {}, - "scope": "resource", "markdownDescription": "%emmetPreferences%", "properties": { "css.intUnit": { diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index 1cac53a6081..2a58c39641d 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -31,7 +31,7 @@ "emmetShowAbbreviationSuggestions": "Shows possible Emmet abbreviations as suggestions. Not applicable in stylesheets or when emmet.showExpandedAbbreviation is set to `\"never\"`.", "emmetIncludeLanguages": "Enable Emmet abbreviations in languages that are not supported by default. Add a mapping here between the language and Emmet supported language.\n For example: `{\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}`", "emmetVariables": "Variables to be used in Emmet snippets.", - "emmetTriggerExpansionOnTab": "When enabled, Emmet abbreviations are expanded when pressing TAB.", + "emmetTriggerExpansionOnTab": "When enabled, Emmet abbreviations are expanded when pressing TAB, even when completions do not show up. When disabled, completions that show up can still be accepted by pressing TAB.", "emmetPreferences": "Preferences used to modify behavior of some actions and resolvers of Emmet.", "emmetPreferencesIntUnit": "Default unit for integer values.", "emmetPreferencesFloatUnit": "Default unit for float values.", @@ -59,5 +59,6 @@ "emmetPreferencesOutputInlineBreak": "The number of sibling inline elements needed for line breaks to be placed between those elements. If `0`, inline elements are always expanded onto a single line.", "emmetPreferencesOutputReverseAttributes": "If `true`, reverses attribute merging directions when resolving snippets.", "emmetPreferencesOutputSelfClosingStyle": "Style of self-closing tags: html (`
`), xml (`
`) or xhtml (`
`).", - "emmetPreferencesCssColorShort": "If `true`, color values like `#f` will be expanded to `#fff` instead of `#ffffff`." + "emmetPreferencesCssColorShort": "If `true`, color values like `#f` will be expanded to `#fff` instead of `#ffffff`.", + "emmetUseInlineCompletions": "If `true`, Emmet will use inline completions to suggest expansions. To prevent the non-inline completion item provider from showing up as often while this setting is `true`, turn `#editor.quickSuggestions#` to `inline` or `off` for the `other` item." } diff --git a/extensions/emmet/src/defaultCompletionProvider.ts b/extensions/emmet/src/defaultCompletionProvider.ts index 1462a2ec4d7..c8a6f657d75 100644 --- a/extensions/emmet/src/defaultCompletionProvider.ts +++ b/extensions/emmet/src/defaultCompletionProvider.ts @@ -49,7 +49,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi const mappedLanguages = getMappingForIncludedLanguages(); const isSyntaxMapped = mappedLanguages[document.languageId] ? true : false; - let emmetMode = getEmmetMode((isSyntaxMapped ? mappedLanguages[document.languageId] : document.languageId), mappedLanguages, excludedLanguages); + const emmetMode = getEmmetMode((isSyntaxMapped ? mappedLanguages[document.languageId] : document.languageId), mappedLanguages, excludedLanguages); if (!emmetMode || emmetConfig['showExpandedAbbreviation'] === 'never' @@ -135,7 +135,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi const offset = document.offsetAt(position); if (isStyleSheet(document.languageId) && context.triggerKind !== vscode.CompletionTriggerKind.TriggerForIncompleteCompletions) { validateLocation = true; - let usePartialParsing = vscode.workspace.getConfiguration('emmet')['optimizeStylesheetParsing'] === true; + const usePartialParsing = vscode.workspace.getConfiguration('emmet')['optimizeStylesheetParsing'] === true; rootNode = usePartialParsing && document.lineCount > 1000 ? parsePartialStylesheet(document, position) : getRootNode(document, true); if (!rootNode) { return; @@ -152,8 +152,8 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi if (!rootNode) { return; } - let flatNode = getFlatNode(rootNode, offset, true); - let embeddedCssNode = getEmbeddedCssNodeIfAny(document, flatNode, position); + const flatNode = getFlatNode(rootNode, offset, true); + const embeddedCssNode = getEmbeddedCssNodeIfAny(document, flatNode, position); currentNode = getFlatNode(embeddedCssNode, offset, true); } @@ -167,7 +167,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi // Check for document symbols in js/ts/jsx/tsx and avoid triggering emmet for abbreviations of the form symbolName.sometext // Presence of > or * or + in the abbreviation denotes valid abbreviation that should trigger emmet if (!isStyleSheet(syntax) && (document.languageId === 'javascript' || document.languageId === 'javascriptreact' || document.languageId === 'typescript' || document.languageId === 'typescriptreact')) { - let abbreviation: string = extractAbbreviationResults.abbreviation; + const abbreviation: string = extractAbbreviationResults.abbreviation; // For the second condition, we don't want abbreviations that have [] characters but not ='s in them to expand // In turn, users must explicitly expand abbreviations of the form Component[attr1 attr2], but it means we don't try to expand a[i]. if (abbreviation.startsWith('this.') || /\[[^\]=]*\]/.test(abbreviation)) { @@ -194,14 +194,14 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi } } - let newItems: vscode.CompletionItem[] = []; + const newItems: vscode.CompletionItem[] = []; if (result && result.items) { result.items.forEach((item: any) => { - let newItem = new vscode.CompletionItem(item.label); + const newItem = new vscode.CompletionItem(item.label); newItem.documentation = item.documentation; newItem.detail = item.detail; newItem.insertText = new vscode.SnippetString(item.textEdit.newText); - let oldrange = item.textEdit.range; + const oldrange = item.textEdit.range; newItem.range = new vscode.Range(oldrange.start.line, oldrange.start.character, oldrange.end.line, oldrange.end.character); newItem.filterText = item.filterText; diff --git a/extensions/emmet/src/editPoint.ts b/extensions/emmet/src/editPoint.ts index 239df1f4cc2..b5137795dc9 100644 --- a/extensions/emmet/src/editPoint.ts +++ b/extensions/emmet/src/editPoint.ts @@ -12,9 +12,9 @@ export function fetchEditPoint(direction: string): void { } const editor = vscode.window.activeTextEditor; - let newSelections: vscode.Selection[] = []; + const newSelections: vscode.Selection[] = []; editor.selections.forEach(selection => { - let updatedSelection = direction === 'next' ? nextEditPoint(selection, editor) : prevEditPoint(selection, editor); + const updatedSelection = direction === 'next' ? nextEditPoint(selection, editor) : prevEditPoint(selection, editor); newSelections.push(updatedSelection); }); editor.selections = newSelections; @@ -23,7 +23,7 @@ export function fetchEditPoint(direction: string): void { function nextEditPoint(selection: vscode.Selection, editor: vscode.TextEditor): vscode.Selection { for (let lineNum = selection.anchor.line; lineNum < editor.document.lineCount; lineNum++) { - let updatedSelection = findEditPoint(lineNum, editor, selection.anchor, 'next'); + const updatedSelection = findEditPoint(lineNum, editor, selection.anchor, 'next'); if (updatedSelection) { return updatedSelection; } @@ -33,7 +33,7 @@ function nextEditPoint(selection: vscode.Selection, editor: vscode.TextEditor): function prevEditPoint(selection: vscode.Selection, editor: vscode.TextEditor): vscode.Selection { for (let lineNum = selection.anchor.line; lineNum >= 0; lineNum--) { - let updatedSelection = findEditPoint(lineNum, editor, selection.anchor, 'prev'); + const updatedSelection = findEditPoint(lineNum, editor, selection.anchor, 'prev'); if (updatedSelection) { return updatedSelection; } @@ -43,7 +43,7 @@ function prevEditPoint(selection: vscode.Selection, editor: vscode.TextEditor): function findEditPoint(lineNum: number, editor: vscode.TextEditor, position: vscode.Position, direction: string): vscode.Selection | undefined { - let line = editor.document.lineAt(lineNum); + const line = editor.document.lineAt(lineNum); let lineContent = line.text; if (lineNum !== position.line && line.isEmptyOrWhitespace && lineContent.length) { @@ -53,8 +53,8 @@ function findEditPoint(lineNum: number, editor: vscode.TextEditor, position: vsc if (lineNum === position.line && direction === 'prev') { lineContent = lineContent.substr(0, position.character); } - let emptyAttrIndex = direction === 'next' ? lineContent.indexOf('""', lineNum === position.line ? position.character : 0) : lineContent.lastIndexOf('""'); - let emptyTagIndex = direction === 'next' ? lineContent.indexOf('><', lineNum === position.line ? position.character : 0) : lineContent.lastIndexOf('><'); + const emptyAttrIndex = direction === 'next' ? lineContent.indexOf('""', lineNum === position.line ? position.character : 0) : lineContent.lastIndexOf('""'); + const emptyTagIndex = direction === 'next' ? lineContent.indexOf('><', lineNum === position.line ? position.character : 0) : lineContent.lastIndexOf('><'); let winner = -1; diff --git a/extensions/emmet/src/emmetCommon.ts b/extensions/emmet/src/emmetCommon.ts index 5a5e0d872c3..daed62d7c65 100644 --- a/extensions/emmet/src/emmetCommon.ts +++ b/extensions/emmet/src/emmetCommon.ts @@ -23,7 +23,7 @@ import { addFileToParseCache, clearParseCache, removeFileFromParseCache } from ' export function activateEmmetExtension(context: vscode.ExtensionContext) { migrateEmmetExtensionsPath(); - registerCompletionProviders(context); + refreshCompletionProviders(context); updateEmmetExtensionsPath(); context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.wrapWithAbbreviation', (args) => { @@ -122,8 +122,8 @@ export function activateEmmetExtension(context: vscode.ExtensionContext) { })); context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => { - if (e.affectsConfiguration('emmet.includeLanguages')) { - registerCompletionProviders(context); + if (e.affectsConfiguration('emmet.includeLanguages') || e.affectsConfiguration('emmet.useInlineCompletions')) { + refreshCompletionProviders(context); } if (e.affectsConfiguration('emmet.extensionsPath')) { updateEmmetExtensionsPath(); @@ -158,45 +158,82 @@ export function activateEmmetExtension(context: vscode.ExtensionContext) { * Holds any registered completion providers by their language strings */ const languageMappingForCompletionProviders: Map = new Map(); -const completionProvidersMapping: Map = new Map(); +const completionProviderDisposables: vscode.Disposable[] = []; -function registerCompletionProviders(context: vscode.ExtensionContext) { - let completionProvider = new DefaultCompletionItemProvider(); - let includedLanguages = getMappingForIncludedLanguages(); +function refreshCompletionProviders(_: vscode.ExtensionContext) { + clearCompletionProviderInfo(); + const completionProvider = new DefaultCompletionItemProvider(); + const inlineCompletionProvider: vscode.InlineCompletionItemProvider = { + async provideInlineCompletionItems(document: vscode.TextDocument, position: vscode.Position, _: vscode.InlineCompletionContext, token: vscode.CancellationToken) { + const items = await completionProvider.provideCompletionItems(document, position, token, { triggerCharacter: undefined, triggerKind: vscode.CompletionTriggerKind.Invoke }); + if (!items) { + return undefined; + } + const item = items.items[0]; + if (!item) { + return undefined; + } + const range = item.range as vscode.Range; + + if (document.getText(range) !== item.label) { + // We only want to show an inline completion if we are really sure the user meant emmet. + // If the user types `d`, we don't want to suggest `
`. + return undefined; + } + + return [ + { + insertText: item.insertText as any, + filterText: item.label as any, + range + } + ]; + } + }; + + const useInlineCompletionProvider = vscode.workspace.getConfiguration('emmet').get('useInlineCompletions'); + const includedLanguages = getMappingForIncludedLanguages(); Object.keys(includedLanguages).forEach(language => { if (languageMappingForCompletionProviders.has(language) && languageMappingForCompletionProviders.get(language) === includedLanguages[language]) { return; } - if (languageMappingForCompletionProviders.has(language)) { - const mapping = completionProvidersMapping.get(language); - if (mapping) { - mapping.dispose(); - } - languageMappingForCompletionProviders.delete(language); - completionProvidersMapping.delete(language); + if (useInlineCompletionProvider) { + const inlineCompletionsProvider = vscode.languages.registerInlineCompletionItemProvider({ language, scheme: '*' }, inlineCompletionProvider); + completionProviderDisposables.push(inlineCompletionsProvider); } - const provider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[includedLanguages[language]]); - context.subscriptions.push(provider); + const explicitProvider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[includedLanguages[language]]); + completionProviderDisposables.push(explicitProvider); languageMappingForCompletionProviders.set(language, includedLanguages[language]); - completionProvidersMapping.set(language, provider); }); Object.keys(LANGUAGE_MODES).forEach(language => { if (!languageMappingForCompletionProviders.has(language)) { - const provider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[language]); - context.subscriptions.push(provider); + if (useInlineCompletionProvider) { + const inlineCompletionsProvider = vscode.languages.registerInlineCompletionItemProvider({ language, scheme: '*' }, inlineCompletionProvider); + completionProviderDisposables.push(inlineCompletionsProvider); + } + + const explicitProvider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[language]); + completionProviderDisposables.push(explicitProvider); languageMappingForCompletionProviders.set(language, language); - completionProvidersMapping.set(language, provider); } }); } +function clearCompletionProviderInfo() { + languageMappingForCompletionProviders.clear(); + let disposable: vscode.Disposable | undefined; + while (disposable = completionProviderDisposables.pop()) { + disposable.dispose(); + } +} + export function deactivate() { - completionProvidersMapping.clear(); + clearCompletionProviderInfo(); clearParseCache(); } diff --git a/extensions/emmet/src/incrementDecrement.ts b/extensions/emmet/src/incrementDecrement.ts index 9e0afa4acf1..f7adf444978 100644 --- a/extensions/emmet/src/incrementDecrement.ts +++ b/extensions/emmet/src/incrementDecrement.ts @@ -21,7 +21,7 @@ export function incrementDecrement(delta: number): Thenable | undefined return editor.edit(editBuilder => { editor.selections.forEach(selection => { - let rangeToReplace = locate(editor.document, selection.isReversed ? selection.anchor : selection.active); + const rangeToReplace = locate(editor.document, selection.isReversed ? selection.anchor : selection.active); if (!rangeToReplace) { return; } @@ -40,7 +40,7 @@ export function incrementDecrement(delta: number): Thenable | undefined */ export function update(numString: string, delta: number): string { let m: RegExpMatchArray | null; - let decimals = (m = numString.match(/\.(\d+)$/)) ? m[1].length : 1; + const decimals = (m = numString.match(/\.(\d+)$/)) ? m[1].length : 1; let output = String((parseFloat(numString) + delta).toFixed(decimals)).replace(/\.0+$/, ''); if (m = numString.match(/^\-?(0\d+)/)) { diff --git a/extensions/emmet/src/matchTag.ts b/extensions/emmet/src/matchTag.ts index d7331a465b2..1c928fb7371 100644 --- a/extensions/emmet/src/matchTag.ts +++ b/extensions/emmet/src/matchTag.ts @@ -20,7 +20,7 @@ export function matchTag() { return; } - let updatedSelections: vscode.Selection[] = []; + const updatedSelections: vscode.Selection[] = []; editor.selections.forEach(selection => { const updatedSelection = getUpdatedSelections(document, rootNode, selection.start); if (updatedSelection) { diff --git a/extensions/emmet/src/removeTag.ts b/extensions/emmet/src/removeTag.ts index c43a9a03e72..b8b5b9eebdf 100644 --- a/extensions/emmet/src/removeTag.ts +++ b/extensions/emmet/src/removeTag.ts @@ -19,7 +19,7 @@ export function removeTag() { return; } - let finalRangesToRemove = Array.from(editor.selections).reverse() + const finalRangesToRemove = Array.from(editor.selections).reverse() .reduce((prev, selection) => prev.concat(getRangesToRemove(editor.document, rootNode, selection)), []); @@ -68,7 +68,7 @@ function getRangesToRemove(document: vscode.TextDocument, rootNode: HtmlFlatNode } } - let rangesToRemove = []; + const rangesToRemove = []; if (openTagRange) { rangesToRemove.push(openTagRange); if (closeTagRange) { diff --git a/extensions/emmet/src/selectItem.ts b/extensions/emmet/src/selectItem.ts index 52e672eddf3..437dbed7ec9 100644 --- a/extensions/emmet/src/selectItem.ts +++ b/extensions/emmet/src/selectItem.ts @@ -21,7 +21,7 @@ export function fetchSelectItem(direction: string): void { return; } - let newSelections: vscode.Selection[] = []; + const newSelections: vscode.Selection[] = []; editor.selections.forEach(selection => { const selectionStart = selection.isReversed ? selection.active : selection.anchor; const selectionEnd = selection.isReversed ? selection.anchor : selection.active; diff --git a/extensions/emmet/src/selectItemStylesheet.ts b/extensions/emmet/src/selectItemStylesheet.ts index 557d971361b..09f45ee8879 100644 --- a/extensions/emmet/src/selectItemStylesheet.ts +++ b/extensions/emmet/src/selectItemStylesheet.ts @@ -28,7 +28,7 @@ export function nextItemStylesheet(document: vscode.TextDocument, startPosition: if (currentNode.type === 'property' && startOffset >= (currentNode).valueToken.start && endOffset <= (currentNode).valueToken.end) { - let singlePropertyValue = getSelectionFromProperty(document, currentNode, startOffset, endOffset, false, 'next'); + const singlePropertyValue = getSelectionFromProperty(document, currentNode, startOffset, endOffset, false, 'next'); if (singlePropertyValue) { return singlePropertyValue; } @@ -77,7 +77,7 @@ export function prevItemStylesheet(document: vscode.TextDocument, startPosition: if (currentNode.type === 'property' && startOffset >= (currentNode).valueToken.start && endOffset <= (currentNode).valueToken.end) { - let singlePropertyValue = getSelectionFromProperty(document, currentNode, startOffset, endOffset, false, 'prev'); + const singlePropertyValue = getSelectionFromProperty(document, currentNode, startOffset, endOffset, false, 'prev'); if (singlePropertyValue) { return singlePropertyValue; } @@ -115,7 +115,7 @@ function getSelectionFromProperty(document: vscode.TextDocument, node: Node | un } const propertyNode = node; - let propertyValue = propertyNode.valueToken.stream.substring(propertyNode.valueToken.start, propertyNode.valueToken.end); + const propertyValue = propertyNode.valueToken.stream.substring(propertyNode.valueToken.start, propertyNode.valueToken.end); selectFullValue = selectFullValue || (direction === 'prev' && selectionStart === propertyNode.valueToken.start && selectionEnd < propertyNode.valueToken.end); @@ -144,7 +144,7 @@ function getSelectionFromProperty(document: vscode.TextDocument, node: Node | un } - let [newSelectionStartOffset, newSelectionEndOffset] = direction === 'prev' ? findPrevWord(propertyValue, pos) : findNextWord(propertyValue, pos); + const [newSelectionStartOffset, newSelectionEndOffset] = direction === 'prev' ? findPrevWord(propertyValue, pos) : findNextWord(propertyValue, pos); if (!newSelectionStartOffset && !newSelectionEndOffset) { return; } diff --git a/extensions/emmet/src/test/abbreviationAction.test.ts b/extensions/emmet/src/test/abbreviationAction.test.ts index c185400bd75..3f18a1ffc5d 100644 --- a/extensions/emmet/src/test/abbreviationAction.test.ts +++ b/extensions/emmet/src/test/abbreviationAction.test.ts @@ -48,7 +48,7 @@ const invokeCompletionContext: CompletionContext = { suite('Tests for Expand Abbreviations (HTML)', () => { const oldValueForExcludeLanguages = workspace.getConfiguration('emmet').inspect('excludeLanguages'); - const oldValueForInlcudeLanguages = workspace.getConfiguration('emmet').inspect('includeLanguages'); + const oldValueForIncludeLanguages = workspace.getConfiguration('emmet').inspect('includeLanguages'); teardown(closeAllEditors); test('Expand snippets (HTML)', () => { @@ -374,7 +374,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { await expandPromise; assert.strictEqual(editor.document.getText(), htmlContents.replace('span.bye', '')); }); - return workspace.getConfiguration('emmet').update('includeLanguages', oldValueForInlcudeLanguages || {}, ConfigurationTarget.Global); + return workspace.getConfiguration('emmet').update('includeLanguages', oldValueForIncludeLanguages || {}, ConfigurationTarget.Global); }); test('Expand html in completion list when inside script tag with javascript type if js is mapped to html (HTML)', async () => { @@ -399,7 +399,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { assert.strictEqual(((emmetCompletionItem.documentation) || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`); return Promise.resolve(); }); - return workspace.getConfiguration('emmet').update('includeLanguages', oldValueForInlcudeLanguages || {}, ConfigurationTarget.Global); + return workspace.getConfiguration('emmet').update('includeLanguages', oldValueForIncludeLanguages || {}, ConfigurationTarget.Global); }); // test('No expanding when html is excluded in the settings', () => { diff --git a/extensions/emmet/src/test/editPointSelectItemBalance.test.ts b/extensions/emmet/src/test/editPointSelectItemBalance.test.ts index b631b156d24..c698e85c683 100644 --- a/extensions/emmet/src/test/editPointSelectItemBalance.test.ts +++ b/extensions/emmet/src/test/editPointSelectItemBalance.test.ts @@ -62,13 +62,13 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => { return withRandomFileEditor(htmlContents, '.html', (editor, _) => { editor.selections = [new Selection(1, 5, 1, 5)]; - let expectedNextEditPoints: [number, number][] = [[4, 16], [6, 8], [10, 2], [10, 2]]; + const expectedNextEditPoints: [number, number][] = [[4, 16], [6, 8], [10, 2], [10, 2]]; expectedNextEditPoints.forEach(([line, col]) => { fetchEditPoint('next'); testSelection(editor.selection, col, line); }); - let expectedPrevEditPoints = [[6, 8], [4, 16], [4, 16]]; + const expectedPrevEditPoints = [[6, 8], [4, 16], [4, 16]]; expectedPrevEditPoints.forEach(([line, col]) => { fetchEditPoint('prev'); testSelection(editor.selection, col, line); @@ -82,7 +82,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => { return withRandomFileEditor(htmlContents, '.html', (editor, _) => { editor.selections = [new Selection(2, 2, 2, 2)]; - let expectedNextItemPoints: [number, number, number][] = [ + const expectedNextItemPoints: [number, number, number][] = [ [2, 1, 5], // html [2, 6, 15], // lang="en" [2, 12, 14], // en @@ -141,7 +141,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => { return withRandomFileEditor(templateContents, '.html', (editor, _) => { editor.selections = [new Selection(2, 2, 2, 2)]; - let expectedNextItemPoints: [number, number, number][] = [ + const expectedNextItemPoints: [number, number, number][] = [ [2, 2, 5], // div [2, 6, 20], // class="header" [2, 13, 19], // header @@ -170,7 +170,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => { return withRandomFileEditor(cssContents, '.css', (editor, _) => { editor.selections = [new Selection(0, 0, 0, 0)]; - let expectedNextItemPoints: [number, number, number][] = [ + const expectedNextItemPoints: [number, number, number][] = [ [1, 0, 4], // .boo [2, 1, 19], // margin: 20px 10px; [2, 9, 18], // 20px 10px @@ -201,7 +201,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => { return withRandomFileEditor(scssContents, '.scss', (editor, _) => { editor.selections = [new Selection(0, 0, 0, 0)]; - let expectedNextItemPoints: [number, number, number][] = [ + const expectedNextItemPoints: [number, number, number][] = [ [1, 0, 4], // .boo [2, 1, 19], // margin: 20px 10px; [2, 9, 18], // 20px 10px @@ -232,7 +232,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => { return withRandomFileEditor(htmlContents, 'html', (editor, _) => { editor.selections = [new Selection(14, 6, 14, 10)]; - let expectedBalanceOutRanges: [number, number, number, number][] = [ + const expectedBalanceOutRanges: [number, number, number, number][] = [ [14, 3, 14, 32], //
  • Item 1
  • [13, 23, 16, 2], // inner contents of