diff --git a/.eslintignore b/.eslintignore index 0299f2c108059..a742b0ae30422 100644 --- a/.eslintignore +++ b/.eslintignore @@ -30,13 +30,6 @@ **/src/vs/*/**/*.d.ts **/src/vs/base/test/common/filters.perf.data.js **/src/vs/loader.js -**/src2/**/dompurify.js -**/src2/**/marked.js -**/src2/**/semver.js -**/src2/typings/**/*.d.ts -**/src2/vs/*/**/*.d.ts -**/src2/vs/base/test/common/filters.perf.data.js -**/src2/vs/loader.js **/test/unit/assert.js **/test/unit/assert-esm.js **/test/automation/out/** diff --git a/.eslintplugin/code-limited-top-functions.ts b/.eslintplugin/code-limited-top-functions.ts new file mode 100644 index 0000000000000..97eef9a6e9d78 --- /dev/null +++ b/.eslintplugin/code-limited-top-functions.ts @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as eslint from 'eslint'; +import { dirname, relative } from 'path'; +import minimatch from 'minimatch'; + +export = new class implements eslint.Rule.RuleModule { + + readonly meta: eslint.Rule.RuleMetaData = { + messages: { + layerbreaker: 'You are only allowed to define limited top level functions.' + }, + schema: { + type: "array", + items: { + type: "object", + additionalProperties: { + type: "array", + items: { + type: "string" + } + } + } + } + }; + + create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { + let fileRelativePath = relative(dirname(__dirname), context.getFilename()); + if (!fileRelativePath.endsWith('/')) { + fileRelativePath += '/'; + } + const ruleArgs = >context.options[0]; + + const matchingKey = Object.keys(ruleArgs).find(key => fileRelativePath.startsWith(key) || minimatch(fileRelativePath, key)); + if (!matchingKey) { + // nothing + return {}; + } + + const restrictedFunctions = ruleArgs[matchingKey]; + + return { + FunctionDeclaration: (node: any) => { + const isTopLevel = node.parent.type === 'Program'; + const functionName = node.id.name; + if (isTopLevel && !restrictedFunctions.includes(node.id.name)) { + context.report({ + node, + message: `Top-level function '${functionName}' is restricted in this file. Allowed functions are: ${restrictedFunctions.join(', ')}.` + }); + } + }, + ExportNamedDeclaration(node: any) { + if (node.declaration && node.declaration.type === 'FunctionDeclaration') { + const functionName = node.declaration.id.name; + const isTopLevel = node.parent.type === 'Program'; + if (isTopLevel && !restrictedFunctions.includes(node.declaration.id.name)) { + context.report({ + node, + message: `Top-level function '${functionName}' is restricted in this file. Allowed functions are: ${restrictedFunctions.join(', ')}.` + }); + } + } + } + } + } +}; diff --git a/.eslintrc.json b/.eslintrc.json index 879d547f9b5a9..27a94df6dcce2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -681,9 +681,7 @@ // - browser // - electron-sandbox "when": "hasBrowser", - "allow": [ - "vs/css!./**/*" - ] + "allow": [] }, { // imports that are allowed in all files of layers: @@ -758,7 +756,6 @@ // imports that are allowed in all /test/ files "when": "test", "allow": [ - "vs/css.build", "vs/css.build.js", "assert", "sinon", @@ -1008,18 +1005,10 @@ "vs/editor/~", "vs/editor/contrib/*/~", "vs/code/~", - { - "when": "hasBrowser", - "pattern": "vs/workbench/workbench.web.main" - }, { "when": "hasBrowser", "pattern": "vs/workbench/workbench.web.main.js" }, - { - "when": "hasBrowser", - "pattern": "vs/workbench/workbench.web.main.internal" - }, { "when": "hasBrowser", "pattern": "vs/workbench/workbench.web.main.internal.js" @@ -1070,13 +1059,11 @@ "vs/platform/*/~", "vs/editor/~", "vs/editor/contrib/*/~", - "vs/editor/editor.all", "vs/editor/editor.all.js", "vs/workbench/~", "vs/workbench/api/~", "vs/workbench/services/*/~", "vs/workbench/contrib/*/~", - "vs/workbench/contrib/terminal/terminal.all", "vs/workbench/contrib/terminal/terminal.all.js" ] }, @@ -1089,13 +1076,11 @@ "vs/platform/*/~", "vs/editor/~", "vs/editor/contrib/*/~", - "vs/editor/editor.all", "vs/editor/editor.all.js", "vs/workbench/~", "vs/workbench/api/~", "vs/workbench/services/*/~", "vs/workbench/contrib/*/~", - "vs/workbench/workbench.common.main", "vs/workbench/workbench.common.main.js" ] }, @@ -1108,13 +1093,11 @@ "vs/platform/*/~", "vs/editor/~", "vs/editor/contrib/*/~", - "vs/editor/editor.all", "vs/editor/editor.all.js", "vs/workbench/~", "vs/workbench/api/~", "vs/workbench/services/*/~", "vs/workbench/contrib/*/~", - "vs/workbench/workbench.common.main", "vs/workbench/workbench.common.main.js" ] }, @@ -1127,13 +1110,11 @@ "vs/platform/*/~", "vs/editor/~", "vs/editor/contrib/*/~", - "vs/editor/editor.all", "vs/editor/editor.all.js", "vs/workbench/~", "vs/workbench/api/~", "vs/workbench/services/*/~", "vs/workbench/contrib/*/~", - "vs/workbench/workbench.common.main", "vs/workbench/workbench.common.main.js" ] }, @@ -1152,7 +1133,7 @@ "restrictions": [] }, { - "target": "src/{bootstrap-amd.js,bootstrap-fork.js,bootstrap-node.js,bootstrap-window.js,cli.js,main.js,server-cli.js,server-main.js,bootstrap-cli.js,bootstrap-server.js}", + "target": "src/{bootstrap-cli.ts,bootstrap-esm.ts,bootstrap-fork.ts,bootstrap-node.ts,bootstrap-import.ts,bootstrap-meta.ts,bootstrap-window.ts,cli.ts,main.ts,server-cli.ts,server-main.ts,bootstrap-server.ts}", "restrictions": [] } ] @@ -1222,6 +1203,15 @@ "**/*" ] } + ], + "local/code-limited-top-functions": [ + "error", + { + "src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts": [ + "webviewPreloads", + "preloadsScriptStr" + ] + } ] } } diff --git a/.vscode/settings.json b/.vscode/settings.json index 1f0f99b5df72a..14236b479e267 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,7 @@ "**/.DS_Store": true, ".vscode-test": true, "cli/target": true, + "build/**/*.js.map": true, "build/**/*.js": { "when": "$(basename).ts" } @@ -41,8 +42,6 @@ "**/yarn.lock": true, "**/package-lock.json": true, "**/Cargo.lock": true, - "src/vs/workbench/workbench.web.main.css": true, - "src/vs/workbench/workbench.desktop.main.css": true, "build/**/*.js": true, "out/**": true, "out-build/**": true, @@ -52,8 +51,7 @@ "extensions/**/out/**": true, "test/smoke/out/**": true, "test/automation/out/**": true, - "test/integration/browser/out/**": true, - "src2/**": true, + "test/integration/browser/out/**": true }, "files.readonlyExclude": { "build/builtin/*.js": true, diff --git a/.vscode/shared.code-snippets b/.vscode/shared.code-snippets index ba36a9f5fcbe2..f473425b76f0c 100644 --- a/.vscode/shared.code-snippets +++ b/.vscode/shared.code-snippets @@ -36,23 +36,5 @@ "private readonly _onDid$1 = new Emitter<$2>();", "readonly onDid$1: Event<$2> = this._onDid$1.event;" ], - }, - "esm-comment": { - "scope": "typescript,javascript", - "prefix": "esm-comment", - "body": [ - "// ESM-comment-begin", - "$SELECTION$0", - "// ESM-comment-end", - ] - }, - "esm-uncomment": { - "scope": "typescript,javascript", - "prefix": "esm-uncomment", - "body": [ - "// ESM-uncomment-begin", - "// $SELECTION$0", - "// ESM-uncomment-end", - ] } } diff --git a/build/azure-pipelines/darwin/product-build-darwin-test.yml b/build/azure-pipelines/darwin/product-build-darwin-test.yml index 937d9d70c3e6f..359aa460a5901 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-test.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-test.yml @@ -7,9 +7,6 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_BUILD_AMD - type: boolean - default: false steps: - script: npm exec -- npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" @@ -20,56 +17,30 @@ steps: - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - script: ./scripts/test-amd.sh --tfs "Unit Tests" - displayName: Run unit tests (Electron) [AMD] - timeoutInMinutes: 15 - - script: npm run test-node-amd - displayName: Run unit tests (node.js) [AMD] - timeoutInMinutes: 15 - - script: npm run test-browser-amd-no-install -- --sequential --browser chromium --browser webkit --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium & Webkit) [AMD] - timeoutInMinutes: 30 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - script: ./scripts/test.sh --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - script: npm run test-node - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - script: npm run test-browser-no-install -- --sequential --browser chromium --browser webkit --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium & Webkit) - timeoutInMinutes: 30 + - script: ./scripts/test.sh --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - script: npm run test-node + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - script: npm run test-browser-no-install -- --sequential --browser chromium --browser webkit --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium & Webkit) + timeoutInMinutes: 30 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - script: ./scripts/test-amd.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) [AMD] - timeoutInMinutes: 15 - - script: npm run test-node-amd -- --build - displayName: Run unit tests (node.js) [AMD] - timeoutInMinutes: 15 - - script: npm run test-browser-amd-no-install -- --sequential --build --browser chromium --browser webkit --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium & Webkit) [AMD] - timeoutInMinutes: 30 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - script: ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - script: npm run test-node -- --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - script: npm run test-browser-no-install -- --sequential --build --browser chromium --browser webkit --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium & Webkit) - timeoutInMinutes: 30 + - script: ./scripts/test.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - script: npm run test-node -- --build + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - script: npm run test-browser-no-install -- --sequential --build --browser chromium --browser webkit --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium & Webkit) + timeoutInMinutes: 30 - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - script: | @@ -94,44 +65,24 @@ steps: displayName: Build integration tests - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - script: ./scripts/test-integration-amd.sh --tfs "Integration Tests" - displayName: Run integration tests (Electron) [AMD] - timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - script: ./scripts/test-integration --tfs "Integration Tests" - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - script: ./scripts/test-integration --tfs "Integration Tests" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, 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" \ - ./scripts/test-integration-amd.sh --build --tfs "Integration Tests" - env: - VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) - displayName: Run integration tests (Electron) [AMD] - timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - 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" \ - ./scripts/test-integration.sh --build --tfs "Integration Tests" - env: - VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - 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" \ + ./scripts/test-integration.sh --build --tfs "Integration Tests" + env: + VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - script: ./scripts/test-web-integration.sh --browser webkit env: diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index a76ab27b5204f..c863c60d5027c 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -9,9 +9,6 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_BUILD_AMD - type: boolean - default: false steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -176,7 +173,6 @@ steps: 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 }} - VSCODE_BUILD_AMD: ${{ parameters.VSCODE_BUILD_AMD }} - ${{ elseif and(ne(parameters.VSCODE_CIBUILD, true), ne(parameters.VSCODE_QUALITY, 'oss')) }}: - task: DownloadPipelineArtifact@2 diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index ee5dd5d99197f..ae11345bb6db6 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -1,5 +1,6 @@ pool: - vmImage: "ubuntu-latest" + name: 1es-ubuntu-22.04-x64 + os: linux trigger: branches: diff --git a/build/azure-pipelines/linux/product-build-linux-legacy-server.yml b/build/azure-pipelines/linux/product-build-linux-legacy-server.yml index ce9d71a529033..649a3d224d9d1 100644 --- a/build/azure-pipelines/linux/product-build-linux-legacy-server.yml +++ b/build/azure-pipelines/linux/product-build-linux-legacy-server.yml @@ -5,9 +5,6 @@ parameters: type: boolean - name: VSCODE_ARCH type: string - - name: VSCODE_BUILD_AMD - type: boolean - default: false steps: - task: NodeTool@0 @@ -206,7 +203,6 @@ steps: VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} VSCODE_RUN_SMOKE_TESTS: false - VSCODE_BUILD_AMD: ${{ parameters.VSCODE_BUILD_AMD }} ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: PUBLISH_TASK_NAME: 1ES.PublishPipelineArtifact@1 diff --git a/build/azure-pipelines/linux/product-build-linux-test.yml b/build/azure-pipelines/linux/product-build-linux-test.yml index 2443e2b1299ec..5f7381d487c47 100644 --- a/build/azure-pipelines/linux/product-build-linux-test.yml +++ b/build/azure-pipelines/linux/product-build-linux-test.yml @@ -10,9 +10,6 @@ parameters: - name: PUBLISH_TASK_NAME type: string default: PublishPipelineArtifact@0 - - name: VSCODE_BUILD_AMD - type: boolean - default: false steps: - script: npm exec -- npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" @@ -36,61 +33,33 @@ steps: - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - script: ./scripts/test-amd.sh --tfs "Unit Tests" - env: - DISPLAY: ":10" - displayName: Run unit tests (Electron) [AMD] - timeoutInMinutes: 15 - - script: npm run test-node-amd - displayName: Run unit tests (node.js) [AMD] - timeoutInMinutes: 15 - - script: npm run test-browser-amd-no-install -- --browser chromium --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium) [AMD] - timeoutInMinutes: 15 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - script: ./scripts/test.sh --tfs "Unit Tests" - env: - DISPLAY: ":10" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - script: npm run test-node - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - script: npm run test-browser-no-install -- --browser chromium --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 15 + - script: ./scripts/test.sh --tfs "Unit Tests" + env: + DISPLAY: ":10" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - script: npm run test-node + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - script: npm run test-browser-no-install -- --browser chromium --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 15 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - script: ./scripts/test-amd.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) [AMD] - timeoutInMinutes: 15 - - script: npm run test-node-amd -- --build - displayName: Run unit tests (node.js) [AMD] - timeoutInMinutes: 15 - - script: npm run test-browser-amd-no-install -- --build --browser chromium --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium) [AMD] - timeoutInMinutes: 15 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - script: ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - script: npm run test-node -- --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - script: npm run test-browser-no-install -- --build --browser chromium --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 15 + - script: ./scripts/test.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - script: npm run test-node -- --build + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - script: npm run test-browser-no-install -- --build --browser chromium --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 15 - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - script: | @@ -116,18 +85,11 @@ steps: - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - script: ./scripts/test-integration-amd.sh --tfs "Integration Tests" - env: - DISPLAY: ":10" - displayName: Run integration tests (Electron) [AMD] - timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - script: ./scripts/test-integration.sh --tfs "Integration Tests" - env: - DISPLAY: ":10" - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - script: ./scripts/test-integration.sh --tfs "Integration Tests" + env: + DISPLAY: ":10" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - script: ./scripts/test-web-integration.sh --browser chromium displayName: Run integration tests (Browser, Chromium) @@ -138,36 +100,20 @@ steps: timeoutInMinutes: 20 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, 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" \ - ./scripts/test-integration-amd.sh --build --tfs "Integration Tests" - env: - VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) - displayName: Run integration tests (Electron) [AMD] - timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - 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" \ - ./scripts/test-integration.sh --build --tfs "Integration Tests" - env: - VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - 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" \ + ./scripts/test-integration.sh --build --tfs "Integration Tests" + env: + VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - script: ./scripts/test-web-integration.sh --browser chromium env: diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 3f53731b70a2b..3fb7b4fe679f3 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -11,9 +11,6 @@ parameters: type: boolean - name: VSCODE_ARCH type: string - - name: VSCODE_BUILD_AMD - type: boolean - default: false steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -290,7 +287,6 @@ steps: 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 }} - VSCODE_BUILD_AMD: ${{ parameters.VSCODE_BUILD_AMD }} ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: PUBLISH_TASK_NAME: 1ES.PublishPipelineArtifact@1 diff --git a/build/azure-pipelines/product-build-pr.yml b/build/azure-pipelines/product-build-pr.yml index 025a1eeac67ce..2d66ff3945d1a 100644 --- a/build/azure-pipelines/product-build-pr.yml +++ b/build/azure-pipelines/product-build-pr.yml @@ -21,8 +21,6 @@ variables: value: oss - name: VSCODE_STEP_ON_IT value: false - - name: VSCODE_BUILD_AMD - value: false jobs: - ${{ if ne(variables['VSCODE_CIBUILD'], true) }}: @@ -50,7 +48,6 @@ jobs: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false @@ -69,7 +66,6 @@ jobs: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true @@ -88,7 +84,6 @@ jobs: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -112,7 +107,6 @@ jobs: - template: win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: true @@ -130,7 +124,6 @@ jobs: - template: win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index d4038dced082b..a061c23e8dc52 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -100,10 +100,6 @@ parameters: displayName: "Skip tests" type: boolean default: false - - name: VSCODE_BUILD_AMD # TODO@bpasero TODO@esm remove me once AMD is removed - displayName: "️❗ Build as AMD (!FOR EMERGENCY ONLY!) ️❗" - type: boolean - default: false variables: - name: VSCODE_PRIVATE_BUILD @@ -114,8 +110,6 @@ variables: value: ${{ parameters.CARGO_REGISTRY }} - name: VSCODE_QUALITY value: ${{ parameters.VSCODE_QUALITY }} - - name: VSCODE_BUILD_AMD - value: ${{ parameters.VSCODE_BUILD_AMD }} - name: VSCODE_BUILD_STAGE_WINDOWS value: ${{ or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_LINUX @@ -225,7 +219,6 @@ extends: - template: build/azure-pipelines/product-compile.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} - ${{ if 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_ALPINE, true),eq(parameters.VSCODE_BUILD_ALPINE_ARM64, true),eq(parameters.VSCODE_BUILD_MACOS, true),eq(parameters.VSCODE_BUILD_MACOS_ARM64, true),eq(parameters.VSCODE_BUILD_WIN32, true),eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}: - stage: CompileCLI @@ -363,7 +356,6 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: true @@ -378,7 +370,6 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false @@ -393,7 +384,6 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false @@ -409,7 +399,6 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -433,7 +422,6 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_ARCH: arm64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false @@ -462,7 +450,6 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false @@ -478,7 +465,6 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true @@ -494,7 +480,6 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -512,7 +497,6 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -538,7 +522,6 @@ extends: parameters: VSCODE_ARCH: armhf VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -554,7 +537,6 @@ extends: parameters: VSCODE_ARCH: arm64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -579,7 +561,6 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF_LEGACY_SERVER, true) }}: @@ -592,7 +573,6 @@ extends: parameters: VSCODE_ARCH: armhf VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_RUN_INTEGRATION_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64_LEGACY_SERVER, true) }}: @@ -605,7 +585,6 @@ extends: parameters: VSCODE_ARCH: arm64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_RUN_INTEGRATION_TESTS: false - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_ALPINE'], true)) }}: @@ -658,7 +637,6 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false @@ -672,7 +650,6 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true @@ -686,7 +663,6 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -701,7 +677,6 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -716,7 +691,6 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -748,7 +722,6 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_AMD: ${{ variables.VSCODE_BUILD_AMD }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index ca8b6a7b3ea1c..facc7af4bc282 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -1,9 +1,6 @@ parameters: - name: VSCODE_QUALITY type: string - - name: VSCODE_BUILD_AMD - type: boolean - default: false steps: - task: NodeTool@0 @@ -103,10 +100,6 @@ steps: - script: node build/azure-pipelines/distro/mixin-quality displayName: Mixin distro quality - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - script: node migrate.mjs --disable-watch --enable-esm-to-amd - displayName: Migrate ESM -> AMD - - template: common/install-builtin-extensions.yml@self - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: diff --git a/build/azure-pipelines/upload-sourcemaps.js b/build/azure-pipelines/upload-sourcemaps.js index 2a01ab79d6bbb..83c1cae596d51 100644 --- a/build/azure-pipelines/upload-sourcemaps.js +++ b/build/azure-pipelines/upload-sourcemaps.js @@ -8,7 +8,6 @@ const path = require("path"); const es = require("event-stream"); const vfs = require("vinyl-fs"); const util = require("../lib/util"); -const amd_1 = require("../lib/amd"); // @ts-ignore const deps = require("../lib/dependencies"); const identity_1 = require("@azure/identity"); @@ -26,9 +25,6 @@ function src(base, maps = `${base}/**/*.map`) { })); } function main() { - if ((0, amd_1.isAMD)()) { - return Promise.resolve(); // in AMD we run into some issues, but we want to unblock the build for recovery - } const sources = []; // vscode client maps (default) if (!base) { diff --git a/build/azure-pipelines/upload-sourcemaps.ts b/build/azure-pipelines/upload-sourcemaps.ts index aed6446d7e53f..8e148c6095f2c 100644 --- a/build/azure-pipelines/upload-sourcemaps.ts +++ b/build/azure-pipelines/upload-sourcemaps.ts @@ -8,7 +8,6 @@ import * as es from 'event-stream'; import * as Vinyl from 'vinyl'; import * as vfs from 'vinyl-fs'; import * as util from '../lib/util'; -import { isAMD } from '../lib/amd'; // @ts-ignore import * as deps from '../lib/dependencies'; import { ClientSecretCredential } from '@azure/identity'; @@ -30,9 +29,6 @@ function src(base: string, maps = `${base}/**/*.map`) { } function main(): Promise { - if (isAMD()) { - return Promise.resolve(); // in AMD we run into some issues, but we want to unblock the build for recovery - } const sources: any[] = []; // vscode client maps (default) diff --git a/build/azure-pipelines/win32/product-build-win32-test.yml b/build/azure-pipelines/win32/product-build-win32-test.yml index 6c6a0949d0d6c..cdcccd7684bc4 100644 --- a/build/azure-pipelines/win32/product-build-win32-test.yml +++ b/build/azure-pipelines/win32/product-build-win32-test.yml @@ -12,9 +12,6 @@ parameters: - name: PUBLISH_TASK_NAME type: string default: PublishPipelineArtifact@0 - - name: VSCODE_BUILD_AMD - type: boolean - default: false steps: - powershell: npm exec -- npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" @@ -25,48 +22,26 @@ steps: - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - powershell: .\scripts\test-amd.bat --tfs "Unit Tests" - displayName: Run unit tests (Electron) [AMD] - timeoutInMinutes: 15 - - powershell: npm run test-node-amd - displayName: Run unit tests (node.js) [AMD] - timeoutInMinutes: 15 - - powershell: node test/unit/browser/index.amd.js --sequential --browser chromium --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser, Chromium) [AMD] - timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - powershell: .\scripts\test.bat --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - powershell: npm run test-node - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - powershell: node test/unit/browser/index.js --sequential --browser chromium --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 20 + - powershell: .\scripts\test.bat --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - powershell: npm run test-node + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - powershell: 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') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - powershell: .\scripts\test-amd.bat --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) [AMD] - timeoutInMinutes: 15 - - script: npm run test-node-amd -- --build - displayName: Run unit tests (node.js) [AMD] - timeoutInMinutes: 15 - - powershell: npm run test-browser-amd-no-install -- --sequential --build --browser chromium --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser, Chromium) [AMD] - timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - powershell: .\scripts\test.bat --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - powershell: npm run test-node -- --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - powershell: npm run test-browser-no-install -- --sequential --build --browser chromium --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 20 + - powershell: .\scripts\test.bat --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - powershell: npm run test-node -- --build + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - powershell: npm run 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: | @@ -98,14 +73,9 @@ steps: condition: succeededOrFailed() - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, true) }}: - - powershell: .\scripts\test-integration-amd.bat --tfs "Integration Tests" - displayName: Run integration tests (Electron) [AMD] - timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - powershell: .\scripts\test-integration.bat --tfs "Integration Tests" - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - powershell: .\scripts\test-integration.bat --tfs "Integration Tests" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - powershell: .\scripts\test-web-integration.bat --browser chromium displayName: Run integration tests (Browser, Chromium) @@ -116,36 +86,20 @@ steps: timeoutInMinutes: 20 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - ${{ if eq(parameters.VSCODE_BUILD_AMD, 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 - $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe" - $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-server-win32-$(VSCODE_ARCH)" - exec { .\scripts\test-integration-amd.bat --build --tfs "Integration Tests" } - displayName: Run integration tests (Electron) [AMD] - timeoutInMinutes: 20 - - ${{ if eq(parameters.VSCODE_BUILD_AMD, false) }}: - - 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 - $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe" - $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-server-win32-$(VSCODE_ARCH)" - exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" } - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - 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 + $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe" + $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-server-win32-$(VSCODE_ARCH)" + exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" } + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - powershell: | . build/azure-pipelines/win32/exec.ps1 diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index dddcb34a89402..a30d4ca8029b2 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -11,9 +11,6 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_BUILD_AMD - type: boolean - default: false steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -182,7 +179,6 @@ steps: 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 }} - VSCODE_BUILD_AMD: ${{ parameters.VSCODE_BUILD_AMD }} ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: PUBLISH_TASK_NAME: 1ES.PublishPipelineArtifact@1 diff --git a/build/buildfile.js b/build/buildfile.js index 0e323ac0fafcd..f4a2a5e322a0f 100644 --- a/build/buildfile.js +++ b/build/buildfile.js @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -const { isAMD } = require('./lib/amd'); - /** * @param {string} name * @param {string[]=} exclude @@ -18,7 +16,7 @@ function createModuleDescription(name, exclude) { } return { - name: name, + name, include: [], exclude: excludes }; @@ -28,40 +26,13 @@ function createModuleDescription(name, exclude) { * @param {string} name */ function createEditorWorkerModuleDescription(name) { - const amdVariant = createModuleDescription(name, ['vs/base/common/worker/simpleWorker', 'vs/editor/common/services/editorSimpleWorker']); - amdVariant.target = 'amd'; - - const esmVariant = { ...amdVariant, dest: undefined }; - esmVariant.target = 'esm'; - esmVariant.name = `${esmVariant.name}.esm`; + const description = createModuleDescription(name, ['vs/base/common/worker/simpleWorker', 'vs/editor/common/services/editorSimpleWorker']); + description.name = `${description.name}.esm`; - return [amdVariant, esmVariant]; + return description; } -// TODO@esm take the editor simple worker top level and rename away from "base" -exports.base = [ - { - name: 'vs/editor/common/services/editorSimpleWorker', - include: ['vs/base/common/worker/simpleWorker'], - exclude: [], - prepend: [ - { path: 'vs/loader.js' }, - { path: 'vs/base/worker/workerMain.js' } - ], - dest: 'vs/base/worker/workerMain.js', - target: 'amd' - }, - { - name: 'vs/editor/common/services/editorSimpleWorker.esm', - target: 'esm' - }, - { - name: 'vs/base/common/worker/simpleWorker', - exclude: [], - target: 'amd' - } -]; - +exports.workerEditor = createEditorWorkerModuleDescription('vs/editor/common/services/editorSimpleWorker'); exports.workerExtensionHost = createEditorWorkerModuleDescription('vs/workbench/api/worker/extensionHostWorker'); exports.workerNotebook = createEditorWorkerModuleDescription('vs/workbench/contrib/notebook/common/services/notebookSimpleWorker'); exports.workerLanguageDetection = createEditorWorkerModuleDescription('vs/workbench/services/languageDetection/browser/languageDetectionSimpleWorker'); @@ -70,34 +41,16 @@ exports.workerProfileAnalysis = createEditorWorkerModuleDescription('vs/platform exports.workerOutputLinks = createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer'); exports.workerBackgroundTokenization = createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker'); -exports.workbenchDesktop = function () { - return !isAMD() ? [ - createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'), - createModuleDescription('vs/platform/files/node/watcher/watcherMain'), - createModuleDescription('vs/platform/terminal/node/ptyHostMain'), - createModuleDescription('vs/workbench/api/node/extensionHostProcess'), - createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'), - createModuleDescription('vs/workbench/workbench.desktop.main') - ] : [ - ...createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer'), - ...createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker'), - createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'), - createModuleDescription('vs/platform/files/node/watcher/watcherMain'), - createModuleDescription('vs/platform/terminal/node/ptyHostMain'), - createModuleDescription('vs/workbench/api/node/extensionHostProcess'), - createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'), - ]; -}; +exports.workbenchDesktop = [ + createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'), + createModuleDescription('vs/platform/files/node/watcher/watcherMain'), + createModuleDescription('vs/platform/terminal/node/ptyHostMain'), + createModuleDescription('vs/workbench/api/node/extensionHostProcess'), + createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'), + createModuleDescription('vs/workbench/workbench.desktop.main') +]; -exports.workbenchWeb = function () { - return !isAMD() ? [ - createModuleDescription('vs/workbench/workbench.web.main') - ] : [ - ...createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer'), - ...createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker'), - createModuleDescription('vs/code/browser/workbench/workbench', ['vs/workbench/workbench.web.main.internal']) - ]; -}; +exports.workbenchWeb = createModuleDescription('vs/workbench/workbench.web.main'); exports.keyboardMaps = [ createModuleDescription('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux'), @@ -113,8 +66,6 @@ exports.code = [ createModuleDescription('vs/code/electron-sandbox/processExplorer/processExplorerMain') ]; -exports.codeWeb = [ - createModuleDescription('vs/code/browser/workbench/workbench') -]; +exports.codeWeb = createModuleDescription('vs/code/browser/workbench/workbench'); exports.entrypoint = createModuleDescription; diff --git a/build/gulpfile.compile.js b/build/gulpfile.compile.js index a8d8fb094b2da..e40b05f8d39ef 100644 --- a/build/gulpfile.compile.js +++ b/build/gulpfile.compile.js @@ -9,12 +9,8 @@ const gulp = require('gulp'); const util = require('./lib/util'); const date = require('./lib/date'); -const amd = require('./lib/amd'); const task = require('./lib/task'); const compilation = require('./lib/compilation'); -const optimize = require('./lib/optimize'); - -const isAMDBuild = typeof process.env.VSCODE_BUILD_AMD === 'string' && process.env.VSCODE_BUILD_AMD.toLowerCase() === 'true'; /** * @param {boolean} disableMangle @@ -22,12 +18,9 @@ const isAMDBuild = typeof process.env.VSCODE_BUILD_AMD === 'string' && process.e function makeCompileBuildTask(disableMangle) { return task.series( util.rimraf('out-build'), - util.buildWebNodePaths('out-build'), date.writeISODate('out-build'), - amd.setAMD(isAMDBuild), compilation.compileApiProposalNamesTask, - compilation.compileTask(isAMDBuild ? 'src2' : 'src', 'out-build', true, { disableMangle }), - optimize.optimizeLoaderTask('out-build', 'out-build', true) + compilation.compileTask('src', 'out-build', true, { disableMangle }) ); } diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 0d55982a8aa19..0a6231dbfb094 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -92,20 +92,10 @@ const compileEditorAMDTask = task.define('compile-editor-amd', compilation.compi const optimizeEditorAMDTask = task.define('optimize-editor-amd', optimize.optimizeTask( { out: 'out-editor', - amd: { + esm: { src: 'out-editor-build', entryPoints: editorEntryPoints, - resources: editorResources, - loaderConfig: { - paths: { - 'vs': 'out-editor-build/vs', - 'vs/css': 'out-editor-build/vs/css.build', - 'vscode': 'empty:' - } - }, - header: BUNDLED_FILE_HEADER, - bundleInfo: true, - languages + resources: editorResources } } )); diff --git a/build/gulpfile.js b/build/gulpfile.js index 5f7b71a40f22a..73f7f23cc0b18 100644 --- a/build/gulpfile.js +++ b/build/gulpfile.js @@ -20,29 +20,25 @@ 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))); +const transpileClientSWCTask = task.define('transpile-client-swc', task.series(util.rimraf('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'))); +const transpileClientTask = task.define('transpile-client', task.series(util.rimraf('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))); +const compileClientTask = task.define('compile-client', task.series(util.rimraf('out'), compileApiProposalNamesTask, compileTask('src', 'out', false))); gulp.task(compileClientTask); -const watchClientTask = task.define('watch-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), task.parallel(watchTask('out', false), watchApiProposalNamesTask))); +const watchClientTask = task.define('watch-client', task.series(util.rimraf('out'), task.parallel(watchTask('out', false), watchApiProposalNamesTask))); gulp.task(watchClientTask); -const watchClientAMDTask = task.define('watch-client-amd', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), task.parallel(watchTask('out', false, 'src2'), watchApiProposalNamesTask))); -gulp.task(watchClientAMDTask); - // All const _compileTask = task.define('compile', task.parallel(monacoTypecheckTask, compileClientTask, compileExtensionsTask, compileExtensionMediaTask)); gulp.task(_compileTask); gulp.task(task.define('watch', task.parallel(/* monacoTypecheckWatchTask, */ watchClientTask, watchExtensionsTask))); -gulp.task(task.define('watch-amd', task.parallel(/* monacoTypecheckWatchTask, */ watchClientAMDTask, watchExtensionsTask))); // Default gulp.task('default', _compileTask); diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index e3147945f84e6..de6d7b4c2aec0 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -31,7 +31,6 @@ const { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require(' const { vscodeWebResourceIncludes, createVSCodeWebFileContentMapper } = require('./gulpfile.vscode.web'); const cp = require('child_process'); const log = require('fancy-log'); -const { isAMD } = require('./lib/amd'); const buildfile = require('./buildfile'); const REPO_ROOT = path.dirname(__dirname); @@ -89,19 +88,15 @@ const serverResources = [ ...serverResourceExcludes ]; -const serverWithWebResourceIncludes = !isAMD() ? [ +const serverWithWebResourceIncludes = [ ...serverResourceIncludes, 'out-build/vs/code/browser/workbench/*.html', ...vscodeWebResourceIncludes -] : [ - ...serverResourceIncludes, - ...vscodeWebResourceIncludes ]; const serverWithWebResourceExcludes = [ ...serverResourceExcludes, - '!out-build/vs/code/**/*-dev.html', - '!out-build/vs/code/**/*-dev.esm.html', + '!out-build/vs/code/**/*-dev.html' ]; const serverWithWebResources = [ @@ -132,8 +127,8 @@ const serverEntryPoints = [ } ]; -const webEntryPoints = !isAMD() ? [ - buildfile.base, +const webEntryPoints = [ + buildfile.workerEditor, buildfile.workerExtensionHost, buildfile.workerNotebook, buildfile.workerLanguageDetection, @@ -142,15 +137,6 @@ const webEntryPoints = !isAMD() ? [ buildfile.workerBackgroundTokenization, buildfile.keyboardMaps, buildfile.codeWeb -].flat() : [ - buildfile.entrypoint('vs/workbench/workbench.web.main.internal'), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.keyboardMaps, - buildfile.workbenchWeb() ].flat(); const serverWithWebEntryPoints = [ @@ -162,10 +148,10 @@ const serverWithWebEntryPoints = [ ...webEntryPoints, ].flat(); -const commonJSEntryPoints = [ +const bootstrapEntryPoints = [ 'out-build/server-main.js', 'out-build/server-cli.js', - 'out-build/bootstrap-fork.js', + 'out-build/bootstrap-fork.js' ]; function getNodeVersion() { @@ -344,7 +330,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa let packageJsonContents; const packageJsonStream = gulp.src(['remote/package.json'], { base: 'remote' }) - .pipe(json({ name, version, dependencies: undefined, optionalDependencies: undefined, ...(!isAMD() ? { type: 'module' } : {}) })) // TODO@esm this should be configured in the top level package.json + .pipe(json({ name, version, dependencies: undefined, optionalDependencies: undefined, ...{ type: 'module' } })) // TODO@esm this should be configured in the top level package.json .pipe(es.through(function (file) { packageJsonContents = file.contents.toString(); this.emit('data', file); @@ -450,7 +436,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa } result = inlineMeta(result, { - targetPaths: commonJSEntryPoints, + targetPaths: bootstrapEntryPoints, packageJsonFn: () => packageJsonContents, productJsonFn: () => productJsonContents }); @@ -474,29 +460,14 @@ function tweakProductForServerWeb(product) { optimize.optimizeTask( { out: `out-vscode-${type}`, - amd: { + esm: { src: 'out-build', - entryPoints: (type === 'reh' ? serverEntryPoints : serverWithWebEntryPoints).flat(), - otherSources: [], + entryPoints: [ + ...(type === 'reh' ? serverEntryPoints : serverWithWebEntryPoints), + ...bootstrapEntryPoints + ], 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: commonJSEntryPoints, - platform: 'node', - external: [ - 'minimist', - // We cannot inline `product.json` from here because - // it is being changed during build time at a later - // point in time (such as `checksums`) - // We have a manual step to inline these later. - '../product.json', - '../package.json' - ] } } ) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 9dfb6a3848c28..03f446fdc2b75 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -33,13 +33,12 @@ const minimist = require('minimist'); const { compileBuildTask } = require('./gulpfile.compile'); const { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require('./gulpfile.extensions'); const { promisify } = require('util'); -const { isAMD } = require('./lib/amd'); const glob = promisify(require('glob')); const rcedit = promisify(require('rcedit')); // Build -const vscodeEntryPoints = !isAMD() ? [ - buildfile.base, +const vscodeEntryPoints = [ + buildfile.workerEditor, buildfile.workerExtensionHost, buildfile.workerNotebook, buildfile.workerLanguageDetection, @@ -47,28 +46,18 @@ const vscodeEntryPoints = !isAMD() ? [ buildfile.workerProfileAnalysis, buildfile.workerOutputLinks, buildfile.workerBackgroundTokenization, - buildfile.workbenchDesktop(), - buildfile.code -].flat() : [ - buildfile.entrypoint('vs/workbench/workbench.desktop.main'), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.workerProfileAnalysis, - buildfile.workbenchDesktop(), + buildfile.workbenchDesktop, buildfile.code ].flat(); -const vscodeResourceIncludes = !isAMD() ? [ +const vscodeResourceIncludes = [ // NLS 'out-build/nls.messages.json', 'out-build/nls.keys.json', // Workbench - 'out-build/vs/code/electron-sandbox/workbench/workbench.esm.html', + 'out-build/vs/code/electron-sandbox/workbench/workbench.html', // Electron Preload 'out-build/vs/base/parts/sandbox/electron-sandbox/preload.js', @@ -105,43 +94,16 @@ const vscodeResourceIncludes = !isAMD() ? [ 'out-build/vs/workbench/contrib/webview/browser/pre/*.{js,html}', // Extension Host Worker - 'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html', + 'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html', // Process Explorer - 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html', + 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.html', // Tree Sitter highlights 'out-build/vs/editor/common/languages/highlights/*.scm', // Issue Reporter - 'out-build/vs/workbench/contrib/issue/electron-sandbox/issueReporter.esm.html' -] : [ - 'out-build/nls.messages.json', - 'out-build/nls.keys.json', - 'out-build/vs/**/*.{svg,png,html,jpg,mp3}', - '!out-build/vs/code/browser/**/*.html', - '!out-build/vs/code/**/*-dev.html', - '!out-build/vs/code/**/*-dev.esm.html', - '!out-build/vs/editor/standalone/**/*.svg', - '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-sandbox/preload.js', - 'out-build/vs/base/parts/sandbox/electron-sandbox/preload-aux.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/common/scripts/fish_xdg_data/fish/vendor_conf.d/*.fish', - 'out-build/vs/workbench/contrib/terminal/common/scripts/*.ps1', - 'out-build/vs/workbench/contrib/terminal/common/scripts/*.psm1', - 'out-build/vs/workbench/contrib/terminal/common/scripts/*.sh', - 'out-build/vs/workbench/contrib/terminal/common/scripts/*.zsh', - 'out-build/vs/workbench/contrib/webview/browser/pre/*.js', - '!out-build/vs/workbench/contrib/issue/**/*-dev.html', - '!out-build/vs/workbench/contrib/issue/**/*-dev.esm.html', - 'out-build/vs/editor/common/languages/highlights/*.scm', - 'out-build/vs/**/markdown.css', - 'out-build/vs/workbench/contrib/tasks/**/*.json', - '!**/test/**' + 'out-build/vs/workbench/contrib/issue/electron-sandbox/issueReporter.html' ]; const vscodeResources = [ @@ -153,22 +115,18 @@ const vscodeResources = [ '!out-build/vs/code/browser/**', '!out-build/vs/editor/standalone/**', '!out-build/vs/code/**/*-dev.html', - '!out-build/vs/code/**/*-dev.esm.html', '!out-build/vs/workbench/contrib/issue/**/*-dev.html', - '!out-build/vs/workbench/contrib/issue/**/*-dev.esm.html', '!**/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 = []; -if (isAMD()) { - windowBootstrapFiles.push('out-build/vs/loader.js'); -} -windowBootstrapFiles.push('out-build/bootstrap-window.js'); +const windowBootstrapFiles = [ + 'out-build/bootstrap-window.js' +]; -const commonJSEntryPoints = [ +const bootstrapEntryPoints = [ 'out-build/main.js', 'out-build/cli.js', 'out-build/bootstrap-fork.js' @@ -177,34 +135,19 @@ const commonJSEntryPoints = [ const optimizeVSCodeTask = task.define('optimize-vscode', task.series( util.rimraf('out-vscode'), // 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. + // 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: { + esm: { src: 'out-build', - entryPoints: vscodeEntryPoints, - resources: vscodeResources, - loaderConfig: optimize.loaderConfig(), - bundleInfo: undefined - }, - commonJS: { - src: 'out-build', - entryPoints: commonJSEntryPoints, - platform: 'node', - external: [ - 'electron', - 'minimist', - 'original-fs', - // We cannot inline `product.json` from here because - // it is being changed during build time at a later - // point in time (such as `checksums`) - // We have a manual step to inline these later. - '../product.json', - '../package.json', - ] + entryPoints: [ + ...vscodeEntryPoints, + ...bootstrapEntryPoints + ], + resources: vscodeResources }, manual: [ { src: [...windowBootstrapFiles, 'out-build/vs/code/electron-sandbox/workbench/workbench.js'], out: 'vs/code/electron-sandbox/workbench/workbench.js' }, @@ -296,7 +239,7 @@ 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', - !isAMD() ? 'vs/code/electron-sandbox/workbench/workbench.esm.html' : 'vs/code/electron-sandbox/workbench/workbench.html', + 'vs/code/electron-sandbox/workbench/workbench.html', 'vs/code/electron-sandbox/workbench/workbench.js' ]); @@ -326,7 +269,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op } const name = product.nameShort; - const packageJsonUpdates = { name, version, ...(!isAMD() ? { type: 'module', main: 'out/main.js' } : {}) }; // TODO@esm this should be configured in the top level package.json + const packageJsonUpdates = { name, version, ...{ type: 'module', main: 'out/main.js' } }; // TODO@esm this should be configured in the top level package.json // for linux url handling if (platform === 'linux') { @@ -377,12 +320,10 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op '**/node-pty/lib/shared/conout.js', '**/*.wasm', '**/@vscode/vsce-sign/bin/*', - ], isAMD() ? [ - '**/*.mk', - ] : [ + ], [ '**/*.mk', '!node_modules/vsda/**' // stay compatible with extensions that depend on us shipping `vsda` into ASAR - ], isAMD() ? [] : [ + ], [ 'node_modules/vsda/**' // retain copy of `vsda` in node_modules for internal use ], 'node_modules.asar')); @@ -489,7 +430,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op } result = inlineMeta(result, { - targetPaths: commonJSEntryPoints, + targetPaths: bootstrapEntryPoints, packageJsonFn: () => packageJsonContents, productJsonFn: () => productJsonContents }); diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index 80b7fc559a4b0..ce65c7e028b2d 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -21,7 +21,6 @@ const vfs = require('vinyl-fs'); const packageJson = require('../package.json'); const { compileBuildTask } = require('./gulpfile.compile'); const extensions = require('./lib/extensions'); -const { isAMD } = require('./lib/amd'); const VinylFile = require('vinyl'); const REPO_ROOT = path.dirname(__dirname); @@ -32,7 +31,7 @@ const commit = getVersion(REPO_ROOT); const quality = product.quality; const version = (quality && quality !== 'stable') ? `${packageJson.version}-${quality}` : packageJson.version; -const vscodeWebResourceIncludes = !isAMD() ? [ +const vscodeWebResourceIncludes = [ // NLS 'out-build/nls.messages.js', @@ -54,30 +53,7 @@ const vscodeWebResourceIncludes = !isAMD() ? [ 'out-build/vs/editor/common/languages/highlights/*.scm', // Extension Host Worker - 'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html', -] : [ - - // Workbench - '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', - - // NLS - 'out-build/nls.messages.js', - - // Webview - 'out-build/vs/workbench/contrib/webview/browser/pre/*.js', - 'out-build/vs/workbench/contrib/webview/browser/pre/*.html', - - // Extension Worker 'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html', - - // Tree Sitter highlights - 'out-build/vs/editor/common/languages/highlights/*.scm', - - // Web node paths (needed for integration tests) - 'out-build/vs/webPackagePaths.js', ]; exports.vscodeWebResourceIncludes = vscodeWebResourceIncludes; @@ -91,14 +67,13 @@ const vscodeWebResources = [ '!out-build/vs/editor/standalone/**', '!out-build/vs/workbench/**/*-tb.png', '!out-build/vs/code/**/*-dev.html', - '!out-build/vs/code/**/*-dev.esm.html', '!**/test/**' ]; const buildfile = require('./buildfile'); -const vscodeWebEntryPoints = !isAMD() ? [ - buildfile.base, +const vscodeWebEntryPoints = [ + buildfile.workerEditor, buildfile.workerExtensionHost, buildfile.workerNotebook, buildfile.workerLanguageDetection, @@ -106,17 +81,8 @@ const vscodeWebEntryPoints = !isAMD() ? [ buildfile.workerOutputLinks, buildfile.workerBackgroundTokenization, buildfile.keyboardMaps, - buildfile.workbenchWeb(), + buildfile.workbenchWeb, buildfile.entrypoint('vs/workbench/workbench.web.main.internal') // TODO@esm remove line when we stop supporting web-amd-esm-bridge -].flat() : [ - buildfile.entrypoint('vs/workbench/workbench.web.main.internal'), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.keyboardMaps, - buildfile.workbenchWeb() ].flat(); /** @@ -198,15 +164,10 @@ const optimizeVSCodeWebTask = task.define('optimize-vscode-web', task.series( optimize.optimizeTask( { out: 'out-vscode-web', - amd: { + esm: { src: 'out-build', - entryPoints: vscodeWebEntryPoints.flat(), - otherSources: [], + entryPoints: vscodeWebEntryPoints, resources: vscodeWebResources, - loaderConfig: optimize.loaderConfig(), - externalLoaderInfo: util.createExternalLoaderConfig(product.webEndpointUrl, commit, quality), - inlineAmdImages: true, - bundleInfo: undefined, fileContentMapper: createVSCodeWebFileContentMapper('.build/web/extensions', product) } } @@ -233,7 +194,7 @@ function packageTask(sourceFolderName, destinationFolderName) { const loader = gulp.src('build/loader.min', { base: 'build', dot: true }).pipe(rename('out/vs/loader.js')); // TODO@esm remove line when we stop supporting web-amd-esm-bridge - const sources = es.merge(...(!isAMD() ? [src, extensions, loader] : [src, extensions])) + const sources = es.merge(src, extensions, loader) .pipe(filter(['**', '!**/*.js.map'], { dot: true })) // TODO@esm remove me once we stop supporting our web-esm-bridge .pipe(es.through(function (file) { diff --git a/build/lib/amd.js b/build/lib/amd.js deleted file mode 100644 index 8d4e428f830cf..0000000000000 --- a/build/lib/amd.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. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.setAMD = setAMD; -exports.isAMD = isAMD; -const path = require("path"); -const fs = require("fs"); -// TODO@esm remove this -const outDirectory = path.join(__dirname, '..', '..', 'out-build'); -const amdMarkerFile = path.join(outDirectory, 'amd'); -function setAMD(enabled) { - const result = () => new Promise((resolve, _) => { - if (enabled) { - fs.mkdirSync(outDirectory, { recursive: true }); - fs.writeFileSync(amdMarkerFile, 'true', 'utf8'); - console.warn(`Setting build to AMD: true`); - } - else { - console.warn(`Setting build to AMD: false`); - } - resolve(); - }); - result.taskName = 'set-amd'; - return result; -} -function isAMD(logWarning) { - try { - const res = (typeof process.env.VSCODE_BUILD_AMD === 'string' && process.env.VSCODE_BUILD_AMD.toLowerCase() === 'true') || (fs.readFileSync(amdMarkerFile, 'utf8') === 'true'); - if (res && logWarning) { - console.warn(`[amd] ${logWarning}`); - } - return res; - } - catch (error) { - return false; - } -} -//# sourceMappingURL=amd.js.map \ No newline at end of file diff --git a/build/lib/amd.ts b/build/lib/amd.ts deleted file mode 100644 index 5373024c6a059..0000000000000 --- a/build/lib/amd.ts +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as path from 'path'; -import * as fs from 'fs'; - -// TODO@esm remove this - -const outDirectory = path.join(__dirname, '..', '..', 'out-build'); -const amdMarkerFile = path.join(outDirectory, 'amd'); - -export function setAMD(enabled: boolean) { - const result = () => new Promise((resolve, _) => { - if (enabled) { - fs.mkdirSync(outDirectory, { recursive: true }); - fs.writeFileSync(amdMarkerFile, 'true', 'utf8'); - console.warn(`Setting build to AMD: true`); - } else { - console.warn(`Setting build to AMD: false`); - } - - resolve(); - }); - result.taskName = 'set-amd'; - return result; -} - -export function isAMD(logWarning?: string): boolean { - try { - const res = (typeof process.env.VSCODE_BUILD_AMD === 'string' && process.env.VSCODE_BUILD_AMD.toLowerCase() === 'true') || (fs.readFileSync(amdMarkerFile, 'utf8') === 'true'); - if (res && logWarning) { - console.warn(`[amd] ${logWarning}`); - } - return res; - } catch (error) { - return false; - } -} diff --git a/build/lib/bundle.ts b/build/lib/bundle.ts index 6e3f96a506294..58995b7d5d1bc 100644 --- a/build/lib/bundle.ts +++ b/build/lib/bundle.ts @@ -51,9 +51,9 @@ export interface IEntryPoint { name: string; include?: string[]; exclude?: string[]; + /** @deprecated unsupported by ESM */ prepend?: IExtraFile[]; dest?: string; - target?: 'amd' | 'esm'; } interface IEntryPointMap { diff --git a/build/lib/layersChecker.js b/build/lib/layersChecker.js index 98241a368b570..ecfe906fa3e9d 100644 --- a/build/lib/layersChecker.js +++ b/build/lib/layersChecker.js @@ -120,6 +120,22 @@ const RULES = [ '@types/node' // no node.js ] }, + // Common: vs/base/common/performance.ts + { + target: '**/vs/base/common/performance.ts', + allowedTypes: [ + ...CORE_TYPES, + // Safe access to Performance + 'Performance', + 'PerformanceEntry', + 'PerformanceTiming' + ], + disallowedTypes: NATIVE_TYPES, + disallowedDefinitions: [ + 'lib.dom.d.ts', // no DOM + '@types/node' // no node.js + ] + }, // Common: vs/platform/environment/common/* { target: '**/vs/platform/environment/common/*.ts', @@ -174,9 +190,9 @@ const RULES = [ '@types/node' // no node.js ] }, - // Common: vs/base/parts/sandbox/electron-sandbox/preload.js + // Common: vs/base/parts/sandbox/electron-sandbox/preload.ts { - target: '**/vs/base/parts/sandbox/electron-sandbox/preload.js', + target: '**/vs/base/parts/sandbox/electron-sandbox/preload.ts', allowedTypes: [ ...CORE_TYPES, // Safe access to a very small subset of node.js diff --git a/build/lib/layersChecker.ts b/build/lib/layersChecker.ts index 26a18a48da735..8a3dd8ed2811b 100644 --- a/build/lib/layersChecker.ts +++ b/build/lib/layersChecker.ts @@ -129,6 +129,24 @@ const RULES: IRule[] = [ ] }, + // Common: vs/base/common/performance.ts + { + target: '**/vs/base/common/performance.ts', + allowedTypes: [ + ...CORE_TYPES, + + // Safe access to Performance + 'Performance', + 'PerformanceEntry', + 'PerformanceTiming' + ], + disallowedTypes: NATIVE_TYPES, + disallowedDefinitions: [ + 'lib.dom.d.ts', // no DOM + '@types/node' // no node.js + ] + }, + // Common: vs/platform/environment/common/* { target: '**/vs/platform/environment/common/*.ts', @@ -189,9 +207,9 @@ const RULES: IRule[] = [ ] }, - // Common: vs/base/parts/sandbox/electron-sandbox/preload.js + // Common: vs/base/parts/sandbox/electron-sandbox/preload.ts { - target: '**/vs/base/parts/sandbox/electron-sandbox/preload.js', + target: '**/vs/base/parts/sandbox/electron-sandbox/preload.ts', allowedTypes: [ ...CORE_TYPES, diff --git a/build/lib/mangle/index.js b/build/lib/mangle/index.js index f429712f10076..70a4cd3ed14fd 100644 --- a/build/lib/mangle/index.js +++ b/build/lib/mangle/index.js @@ -14,7 +14,6 @@ const ts = require("typescript"); const url_1 = require("url"); const workerpool = require("workerpool"); const staticLanguageServiceHost_1 = require("./staticLanguageServiceHost"); -const amd_1 = require("../amd"); const buildfile = require('../../buildfile'); class ShortIdent { prefix; @@ -248,51 +247,37 @@ function isNameTakenInFile(node, name) { } return false; } -const skippedExportMangledFiles = function () { - return [ - // Build - 'css.build', - // Monaco - 'editorCommon', - 'editorOptions', - 'editorZoom', - 'standaloneEditor', - 'standaloneEnums', - 'standaloneLanguages', - // Generated - 'extensionsApiProposals', - // Module passed around as type - 'pfs', - // entry points - ...!(0, amd_1.isAMD)() ? [ - buildfile.entrypoint('vs/server/node/server.main'), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.workerProfileAnalysis, - buildfile.workerOutputLinks, - buildfile.workerBackgroundTokenization, - buildfile.workbenchDesktop(), - buildfile.workbenchWeb(), - buildfile.code, - buildfile.codeWeb - ].flat().map(x => x.name) : [ - buildfile.entrypoint('vs/server/node/server.main'), - buildfile.entrypoint('vs/workbench/workbench.desktop.main'), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.workerProfileAnalysis, - buildfile.workbenchDesktop(), - buildfile.workbenchWeb(), - buildfile.code - ].flat().map(x => x.name), - ]; -}; +const skippedExportMangledFiles = [ + // Build + 'css.build', + // Monaco + 'editorCommon', + 'editorOptions', + 'editorZoom', + 'standaloneEditor', + 'standaloneEnums', + 'standaloneLanguages', + // Generated + 'extensionsApiProposals', + // Module passed around as type + 'pfs', + // entry points + ...[ + buildfile.entrypoint('vs/server/node/server.main'), + buildfile.workerEditor, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, + buildfile.workerOutputLinks, + buildfile.workerBackgroundTokenization, + buildfile.workbenchDesktop, + buildfile.workbenchWeb, + buildfile.code, + buildfile.codeWeb + ].flat().map(x => x.name), +]; const skippedExportMangledProjects = [ // Test projects 'vscode-api-tests', @@ -536,7 +521,7 @@ class Mangler { for (const data of this.allExportedSymbols.values()) { if (data.fileName.endsWith('.d.ts') || skippedExportMangledProjects.some(proj => data.fileName.includes(proj)) - || skippedExportMangledFiles().some(file => data.fileName.endsWith(file + '.ts'))) { + || skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts'))) { continue; } if (!data.shouldMangle(data.replacementName)) { diff --git a/build/lib/mangle/index.ts b/build/lib/mangle/index.ts index ecede4cc10801..0289cf2f97283 100644 --- a/build/lib/mangle/index.ts +++ b/build/lib/mangle/index.ts @@ -12,7 +12,6 @@ import * as ts from 'typescript'; import { pathToFileURL } from 'url'; import * as workerpool from 'workerpool'; import { StaticLanguageServiceHost } from './staticLanguageServiceHost'; -import { isAMD } from '../amd'; const buildfile = require('../../buildfile'); class ShortIdent { @@ -280,55 +279,41 @@ function isNameTakenInFile(node: ts.Node, name: string): boolean { return false; } -const skippedExportMangledFiles = function () { // using a function() to ensure late isAMD() check - return [ - // Build - 'css.build', - - // Monaco - 'editorCommon', - 'editorOptions', - 'editorZoom', - 'standaloneEditor', - 'standaloneEnums', - 'standaloneLanguages', - - // Generated - 'extensionsApiProposals', - - // Module passed around as type - 'pfs', - - // entry points - ...!isAMD() ? [ - buildfile.entrypoint('vs/server/node/server.main'), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.workerProfileAnalysis, - buildfile.workerOutputLinks, - buildfile.workerBackgroundTokenization, - buildfile.workbenchDesktop(), - buildfile.workbenchWeb(), - buildfile.code, - buildfile.codeWeb - ].flat().map(x => x.name) : [ - buildfile.entrypoint('vs/server/node/server.main'), - buildfile.entrypoint('vs/workbench/workbench.desktop.main'), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.workerProfileAnalysis, - buildfile.workbenchDesktop(), - buildfile.workbenchWeb(), - buildfile.code - ].flat().map(x => x.name), - ]; -}; +const skippedExportMangledFiles = [ + // Build + 'css.build', + + // Monaco + 'editorCommon', + 'editorOptions', + 'editorZoom', + 'standaloneEditor', + 'standaloneEnums', + 'standaloneLanguages', + + // Generated + 'extensionsApiProposals', + + // Module passed around as type + 'pfs', + + // entry points + ...[ + buildfile.entrypoint('vs/server/node/server.main'), + buildfile.workerEditor, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, + buildfile.workerOutputLinks, + buildfile.workerBackgroundTokenization, + buildfile.workbenchDesktop, + buildfile.workbenchWeb, + buildfile.code, + buildfile.codeWeb + ].flat().map(x => x.name), +]; const skippedExportMangledProjects = [ // Test projects @@ -625,7 +610,7 @@ export class Mangler { for (const data of this.allExportedSymbols.values()) { if (data.fileName.endsWith('.d.ts') || skippedExportMangledProjects.some(proj => data.fileName.includes(proj)) - || skippedExportMangledFiles().some(file => data.fileName.endsWith(file + '.ts')) + || skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts')) ) { continue; } diff --git a/build/lib/nls.js b/build/lib/nls.js index 00b9c9262fa9b..6ddcd46167a9b 100644 --- a/build/lib/nls.js +++ b/build/lib/nls.js @@ -11,7 +11,6 @@ const File = require("vinyl"); const sm = require("source-map"); const path = require("path"); const sort = require("gulp-sort"); -const amd_1 = require("./amd"); var CollectStepResult; (function (CollectStepResult) { CollectStepResult[CollectStepResult["Yes"] = 0] = "Yes"; @@ -170,23 +169,13 @@ var _nls; .filter(n => n.kind === ts.SyntaxKind.ImportEqualsDeclaration) .map(n => n) .filter(d => d.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference) - .filter(d => { - if (!(0, amd_1.isAMD)()) { - return d.moduleReference.expression.getText().endsWith(`/nls.js'`); - } - return d.moduleReference.expression.getText().endsWith(`/nls'`); - }); + .filter(d => d.moduleReference.expression.getText().endsWith(`/nls.js'`)); // import ... from 'vs/nls'; const importDeclarations = imports .filter(n => n.kind === ts.SyntaxKind.ImportDeclaration) .map(n => n) .filter(d => d.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral) - .filter(d => { - if (!(0, amd_1.isAMD)()) { - return d.moduleSpecifier.getText().endsWith(`/nls.js'`); - } - return d.moduleSpecifier.getText().endsWith(`/nls'`); - }) + .filter(d => d.moduleSpecifier.getText().endsWith(`/nls.js'`)) .filter(d => !!d.importClause && !!d.importClause.namedBindings); // `nls.localize(...)` calls const nlsLocalizeCallExpressions = importDeclarations diff --git a/build/lib/nls.ts b/build/lib/nls.ts index a861122b1bbbc..4600fe43dc24f 100644 --- a/build/lib/nls.ts +++ b/build/lib/nls.ts @@ -10,7 +10,6 @@ import * as File from 'vinyl'; import * as sm from 'source-map'; import * as path from 'path'; import * as sort from 'gulp-sort'; -import { isAMD } from './amd'; declare class FileSourceMap extends File { public sourceMap: sm.RawSourceMap; @@ -232,24 +231,14 @@ module _nls { .filter(n => n.kind === ts.SyntaxKind.ImportEqualsDeclaration) .map(n => n) .filter(d => d.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference) - .filter(d => { - if (!isAMD()) { - return (d.moduleReference).expression.getText().endsWith(`/nls.js'`); - } - return (d.moduleReference).expression.getText().endsWith(`/nls'`); - }); + .filter(d => (d.moduleReference).expression.getText().endsWith(`/nls.js'`)); // import ... from 'vs/nls'; const importDeclarations = imports .filter(n => n.kind === ts.SyntaxKind.ImportDeclaration) .map(n => n) .filter(d => d.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral) - .filter(d => { - if (!isAMD()) { - return d.moduleSpecifier.getText().endsWith(`/nls.js'`); - } - return d.moduleSpecifier.getText().endsWith(`/nls'`); - }) + .filter(d => d.moduleSpecifier.getText().endsWith(`/nls.js'`)) .filter(d => !!d.importClause && !!d.importClause.namedBindings); // `nls.localize(...)` calls diff --git a/build/lib/optimize.js b/build/lib/optimize.js index 8003b5763c4b8..f04709fa49df4 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -4,206 +4,35 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.loaderConfig = loaderConfig; -exports.optimizeLoaderTask = optimizeLoaderTask; exports.optimizeTask = optimizeTask; exports.minifyTask = minifyTask; const es = require("event-stream"); const gulp = require("gulp"); const concat = require("gulp-concat"); const filter = require("gulp-filter"); -const fancyLog = require("fancy-log"); -const ansiColors = require("ansi-colors"); const path = require("path"); const fs = require("fs"); const pump = require("pump"); const VinylFile = require("vinyl"); const bundle = require("./bundle"); -const i18n_1 = require("./i18n"); -const stats_1 = require("./stats"); -const util = require("./util"); const postcss_1 = require("./postcss"); const esbuild = require("esbuild"); const sourcemaps = require("gulp-sourcemaps"); -const amd_1 = require("./amd"); const REPO_ROOT_PATH = path.join(__dirname, '../..'); -function log(prefix, message) { - fancyLog(ansiColors.cyan('[' + prefix + ']'), message); -} -function loaderConfig() { - const result = { - paths: { - 'vs': 'out-build/vs', - 'vscode': 'empty:' - }, - amdModulesPattern: /^vs\// - }; - result['vs/css'] = { inlineResources: true }; - return result; -} -const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i; -function loaderPlugin(src, base, amdModuleId) { - return (gulp - .src(src, { base }) - .pipe(es.through(function (data) { - 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, 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')); - } - const files = []; - const order = (f) => { - if (f.path.endsWith('loader.js')) { - return 0; - } - if (f.path.endsWith('css.js')) { - return 1; - } - return 2; - }; - 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) { - files.push(new VinylFile({ - path: 'fake2', - base: '.', - contents: Buffer.from(emitExternalLoaderInfo(externalLoaderInfo)) - })); - } - for (const file of files) { - this.emit('data', file); - } - this.emit('end'); - })) - .pipe(concat('vs/loader.js'))); -} -function emitExternalLoaderInfo(externalLoaderInfo) { - const externalBaseUrl = externalLoaderInfo.baseUrl; - externalLoaderInfo.baseUrl = '$BASE_URL'; - // If defined, use the runtime configured baseUrl. - const code = ` -(function() { - const baseUrl = require.getConfig().baseUrl || ${JSON.stringify(externalBaseUrl)}; - require.config(${JSON.stringify(externalLoaderInfo, undefined, 2)}); -})();`; - return code.replace('"$BASE_URL"', 'baseUrl'); -} -function toConcatStream(src, bundledFileHeader, sources, dest, fileContentMapper) { - const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest); - // If a bundle ends up including in any of the sources our copyright, then - // insert a fake source at the beginning of each bundle with our copyright - let containsOurCopyright = false; - for (let i = 0, len = sources.length; i < len; i++) { - const fileContents = sources[i].contents; - if (IS_OUR_COPYRIGHT_REGEXP.test(fileContents)) { - containsOurCopyright = true; - break; - } - } - if (containsOurCopyright) { - sources.unshift({ - path: null, - contents: bundledFileHeader - }); - } - const treatedSources = sources.map(function (source) { - const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : ''; - const base = source.path ? root + `/${src}` : '.'; - const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake'; - const contents = source.path ? fileContentMapper(source.contents, path) : source.contents; - return new VinylFile({ - path: path, - base: base, - contents: Buffer.from(contents) - }); - }); - return es.readArray(treatedSources) - .pipe(useSourcemaps ? util.loadSourcemaps() : es.through()) - .pipe(concat(dest)) - .pipe((0, stats_1.createStatsStream)(dest)); -} -function toBundleStream(src, bundledFileHeader, bundles, fileContentMapper) { - return es.merge(bundles.map(function (bundle) { - return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper); - })); -} const DEFAULT_FILE_HEADER = [ '/*!--------------------------------------------------------', ' * Copyright (C) Microsoft Corporation. All rights reserved.', ' *--------------------------------------------------------*/' ].join('\n'); -function optimizeAMDTask(opts) { - const src = opts.src; - const entryPoints = opts.entryPoints.filter(d => d.target !== 'esm'); - const resources = opts.resources; - const loaderConfig = opts.loaderConfig; - const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; - const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents); - const bundlesStream = es.through(); // this stream will contain the bundled files +function optimizeESMTask(opts) { 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); - } - 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')) - })); + const bundlesStream = es.through(); // this stream will contain the bundled files + const entryPoints = opts.entryPoints.map(entryPoint => { + if (typeof entryPoint === 'string') { + return { name: path.parse(entryPoint).name }; } - es.readArray(bundleInfoArray).pipe(bundleInfoStream); + return entryPoint; }); - 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)({ - out: opts.src, - fileHeader: bundledFileHeader, - languages: opts.languages - }) : es.through()); -} -function optimizeESMTask(opts, cjsOpts) { - const resourcesStream = es.through(); // this stream will contain the resources - const bundlesStream = es.through(); // this stream will contain the bundled files - const entryPoints = opts.entryPoints.filter(d => d.target !== 'amd'); - if (cjsOpts) { - cjsOpts.entryPoints.forEach(entryPoint => entryPoints.push({ name: path.parse(entryPoint).name })); - } const allMentionedModules = new Set(); for (const entryPoint of entryPoints) { allMentionedModules.add(entryPoint.name); @@ -235,14 +64,6 @@ function optimizeESMTask(opts, cjsOpts) { }); } }; - // support for 'preprend' via the esbuild#banner - if (entryPoint.prepend?.length) { - for (const item of entryPoint.prepend) { - const fullpath = path.join(REPO_ROOT_PATH, opts.src, item.path); - const source = await fs.promises.readFile(fullpath, 'utf8'); - banner.js += source + '\n'; - } - } const task = esbuild.build({ bundle: true, external: entryPoint.exclude, @@ -295,7 +116,6 @@ function optimizeESMTask(opts, cjsOpts) { files.push(new VinylFile(fileProps)); } }); - // await task; // FORCE serial bundling (makes debugging easier) tasks.push(task); } await Promise.all(tasks); @@ -305,7 +125,7 @@ function optimizeESMTask(opts, cjsOpts) { // bundle output (JS, CSS, SVG...) es.readArray(output.files).pipe(bundlesStream); // forward all resources - gulp.src(opts.resources, { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream); + gulp.src(opts.resources ?? [], { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream); }); const result = es.merge(bundlesStream, resourcesStream); return result @@ -313,29 +133,6 @@ function optimizeESMTask(opts, cjsOpts) { sourceRoot: undefined, addComment: true, includeContent: true - })) - .pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({ - out: opts.src, - fileHeader: opts.header || DEFAULT_FILE_HEADER, - languages: opts.languages - }) : es.through()); -} -function optimizeCommonJSTask(opts) { - 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) { @@ -346,21 +143,10 @@ function optimizeManualTask(options) { }); return es.merge(...concatenations); } -function optimizeLoaderTask(src, out, bundleLoader, bundledFileHeader = '', externalLoaderInfo) { - return () => loader(src, bundledFileHeader, bundleLoader, externalLoaderInfo).pipe(gulp.dest(out)); -} function optimizeTask(opts) { return function () { const optimizers = []; - if (!(0, amd_1.isAMD)()) { - optimizers.push(optimizeESMTask(opts.amd, opts.commonJS)); - } - else { - optimizers.push(optimizeAMDTask(opts.amd)); - if (opts.commonJS) { - optimizers.push(optimizeCommonJSTask(opts.commonJS)); - } - } + optimizers.push(optimizeESMTask(opts.esm)); if (opts.manual) { optimizers.push(optimizeManualTask(opts.manual)); } diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index 3cb778111ae6b..60318c277ba4a 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -7,200 +7,30 @@ import * as es from 'event-stream'; import * as gulp from 'gulp'; import * as concat from 'gulp-concat'; import * as filter from 'gulp-filter'; -import * as fancyLog from 'fancy-log'; -import * as ansiColors from 'ansi-colors'; import * as path from 'path'; import * as fs from 'fs'; import * as pump from 'pump'; import * as VinylFile from 'vinyl'; import * as bundle from './bundle'; -import { Language, processNlsFiles } from './i18n'; -import { createStatsStream } from './stats'; -import * as util from './util'; import { gulpPostcss } from './postcss'; import * as esbuild from 'esbuild'; import * as sourcemaps from 'gulp-sourcemaps'; -import { isAMD } from './amd'; const REPO_ROOT_PATH = path.join(__dirname, '../..'); -function log(prefix: string, message: string): void { - fancyLog(ansiColors.cyan('[' + prefix + ']'), message); -} - -export function loaderConfig() { - const result: any = { - paths: { - 'vs': 'out-build/vs', - 'vscode': 'empty:' - }, - amdModulesPattern: /^vs\// - }; - - result['vs/css'] = { inlineResources: true }; - - return result; -} - -const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i; - -function loaderPlugin(src: string, base: string, amdModuleId: string | undefined): NodeJS.ReadWriteStream { - return ( - gulp - .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?: util.IExternalLoaderInfo): 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') - ); - } - - const files: VinylFile[] = []; - const order = (f: VinylFile) => { - if (f.path.endsWith('loader.js')) { - return 0; - } - if (f.path.endsWith('css.js')) { - return 1; - } - return 2; - }; - - 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) { - files.push(new VinylFile({ - path: 'fake2', - base: '.', - contents: Buffer.from(emitExternalLoaderInfo(externalLoaderInfo)) - })); - } - for (const file of files) { - this.emit('data', file); - } - this.emit('end'); - })) - .pipe(concat('vs/loader.js')) - ); -} - -function emitExternalLoaderInfo(externalLoaderInfo: util.IExternalLoaderInfo): string { - const externalBaseUrl = externalLoaderInfo.baseUrl; - externalLoaderInfo.baseUrl = '$BASE_URL'; - - // If defined, use the runtime configured baseUrl. - const code = ` -(function() { - const baseUrl = require.getConfig().baseUrl || ${JSON.stringify(externalBaseUrl)}; - require.config(${JSON.stringify(externalLoaderInfo, undefined, 2)}); -})();`; - return code.replace('"$BASE_URL"', 'baseUrl'); -} - -function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.IFile[], dest: string, fileContentMapper: (contents: string, path: string) => string): NodeJS.ReadWriteStream { - const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest); - - // If a bundle ends up including in any of the sources our copyright, then - // insert a fake source at the beginning of each bundle with our copyright - let containsOurCopyright = false; - for (let i = 0, len = sources.length; i < len; i++) { - const fileContents = sources[i].contents; - if (IS_OUR_COPYRIGHT_REGEXP.test(fileContents)) { - containsOurCopyright = true; - break; - } - } - - if (containsOurCopyright) { - sources.unshift({ - path: null, - contents: bundledFileHeader - }); - } - - const treatedSources = sources.map(function (source) { - const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : ''; - const base = source.path ? root + `/${src}` : '.'; - const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake'; - const contents = source.path ? fileContentMapper(source.contents, path) : source.contents; - - return new VinylFile({ - path: path, - base: base, - contents: Buffer.from(contents) - }); - }); - - return es.readArray(treatedSources) - .pipe(useSourcemaps ? util.loadSourcemaps() : es.through()) - .pipe(concat(dest)) - .pipe(createStatsStream(dest)); -} - -function toBundleStream(src: string, bundledFileHeader: string, bundles: bundle.IConcatFile[], fileContentMapper: (contents: string, path: string) => string): NodeJS.ReadWriteStream { - return es.merge(bundles.map(function (bundle) { - return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper); - })); -} - -export interface IOptimizeAMDTaskOpts { +export interface IOptimizeESMTaskOpts { /** * The folder to read files from. */ src: string; /** - * (for AMD files, will get bundled and get Copyright treatment) + * The entry points to bundle. */ - entryPoints: bundle.IEntryPoint[]; + entryPoints: Array; /** - * (svg, etc.) + * Other resources to consider (svg, etc.) */ - resources: string[]; - loaderConfig: any; - /** - * Additional info we append to the end of the loader - */ - externalLoaderInfo?: util.IExternalLoaderInfo; - /** - * (true by default - append css and nls to loader) - */ - bundleLoader?: boolean; - /** - * (basically the Copyright treatment) - */ - header?: string; - /** - * (emit bundleInfo.json file) - */ - bundleInfo: boolean; - /** - * Language configuration. - */ - languages?: Language[]; + resources?: string[]; /** * File contents interceptor * @param contents The contents of the file @@ -215,72 +45,16 @@ const DEFAULT_FILE_HEADER = [ ' *--------------------------------------------------------*/' ].join('\n'); -function optimizeAMDTask(opts: IOptimizeAMDTaskOpts): NodeJS.ReadWriteStream { - const src = opts.src; - const entryPoints = opts.entryPoints.filter(d => d.target !== 'esm'); - const resources = opts.resources; - const loaderConfig = opts.loaderConfig; - const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; - const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents); - - 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); - } - 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')) - })); - } - 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 ? processNlsFiles({ - out: opts.src, - fileHeader: bundledFileHeader, - languages: opts.languages - }) : es.through()); -} - -function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJSTaskOpts): NodeJS.ReadWriteStream { +function optimizeESMTask(opts: IOptimizeESMTaskOpts): NodeJS.ReadWriteStream { const resourcesStream = es.through(); // this stream will contain the resources const bundlesStream = es.through(); // this stream will contain the bundled files - const entryPoints = opts.entryPoints.filter(d => d.target !== 'amd'); - if (cjsOpts) { - cjsOpts.entryPoints.forEach(entryPoint => entryPoints.push({ name: path.parse(entryPoint).name })); - } + const entryPoints = opts.entryPoints.map(entryPoint => { + if (typeof entryPoint === 'string') { + return { name: path.parse(entryPoint).name }; + } + return entryPoint; + }); const allMentionedModules = new Set(); for (const entryPoint of entryPoints) { @@ -322,15 +96,6 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS } }; - // support for 'preprend' via the esbuild#banner - if (entryPoint.prepend?.length) { - for (const item of entryPoint.prepend) { - const fullpath = path.join(REPO_ROOT_PATH, opts.src, item.path); - const source = await fs.promises.readFile(fullpath, 'utf8'); - banner.js += source + '\n'; - } - } - const task = esbuild.build({ bundle: true, external: entryPoint.exclude, @@ -390,7 +155,6 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS } }); - // await task; // FORCE serial bundling (makes debugging easier) tasks.push(task); } @@ -404,7 +168,7 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS es.readArray(output.files).pipe(bundlesStream); // forward all resources - gulp.src(opts.resources, { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream); + gulp.src(opts.resources ?? [], { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream); }); const result = es.merge( @@ -417,51 +181,6 @@ function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJS sourceRoot: undefined, addComment: true, includeContent: true - })) - .pipe(opts.languages && opts.languages.length ? processNlsFiles({ - out: opts.src, - fileHeader: opts.header || DEFAULT_FILE_HEADER, - 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 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); - }); })); } @@ -487,23 +206,15 @@ function optimizeManualTask(options: IOptimizeManualTaskOpts[]): NodeJS.ReadWrit return es.merge(...concatenations); } -export function optimizeLoaderTask(src: string, out: string, bundleLoader: boolean, bundledFileHeader = '', externalLoaderInfo?: util.IExternalLoaderInfo): () => 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 ESM modules (using esbuild). + */ + esm: IOptimizeESMTaskOpts; /** * Optimize manually by concatenating files. */ @@ -513,15 +224,7 @@ export interface IOptimizeTaskOpts { export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream { return function () { const optimizers: NodeJS.ReadWriteStream[] = []; - if (!isAMD()) { - optimizers.push(optimizeESMTask(opts.amd, opts.commonJS)); - } else { - optimizers.push(optimizeAMDTask(opts.amd)); - - if (opts.commonJS) { - optimizers.push(optimizeCommonJSTask(opts.commonJS)); - } - } + optimizers.push(optimizeESMTask(opts.esm)); if (opts.manual) { optimizers.push(optimizeManualTask(opts.manual)); diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index 56aa02ebfb752..8e5ac9f6143e7 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -150,6 +150,7 @@ "--vscode-editor-placeholder-foreground", "--vscode-editor-rangeHighlightBackground", "--vscode-editor-rangeHighlightBorder", + "--vscode-editor-compositionBorder", "--vscode-editor-selectionBackground", "--vscode-editor-selectionForeground", "--vscode-editor-selectionHighlightBackground", diff --git a/build/lib/tsb/transpiler.js b/build/lib/tsb/transpiler.js index 5dcc4ca1ed389..100b1bac972ae 100644 --- a/build/lib/tsb/transpiler.js +++ b/build/lib/tsb/transpiler.js @@ -62,7 +62,7 @@ class OutputFileNameOracle { catch (err) { console.error(file, cmdLine.fileNames); console.error(err); - throw new err; + throw err; } }; } diff --git a/build/lib/tsb/transpiler.ts b/build/lib/tsb/transpiler.ts index cbc3d9e8eeeb6..b6a9deeb3c76d 100644 --- a/build/lib/tsb/transpiler.ts +++ b/build/lib/tsb/transpiler.ts @@ -84,7 +84,7 @@ class OutputFileNameOracle { } catch (err) { console.error(file, cmdLine.fileNames); console.error(err); - throw new err; + throw err; } }; } diff --git a/build/lib/util.js b/build/lib/util.js index 09df0e69e3f4a..82e4189dd1a74 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -21,12 +21,8 @@ exports.rreddir = rreddir; exports.ensureDir = ensureDir; exports.rebase = rebase; exports.filter = filter; -exports.versionStringToNumber = versionStringToNumber; exports.streamToPromise = streamToPromise; exports.getElectronVersion = getElectronVersion; -exports.acquireWebNodePaths = acquireWebNodePaths; -exports.createExternalLoaderConfig = createExternalLoaderConfig; -exports.buildWebNodePaths = buildWebNodePaths; const es = require("event-stream"); const _debounce = require("debounce"); const _filter = require("gulp-filter"); @@ -300,14 +296,6 @@ function filter(fn) { result.restore = es.through(); return result; } -function versionStringToNumber(versionStr) { - const semverRegex = /(\d+)\.(\d+)\.(\d+)/; - const match = versionStr.match(semverRegex); - if (!match) { - throw new Error('Version string is not properly formatted: ' + versionStr); - } - return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10); -} function streamToPromise(stream) { return new Promise((c, e) => { stream.on('error', err => e(err)); @@ -320,88 +308,4 @@ function getElectronVersion() { const msBuildId = /^ms_build_id="(.*)"$/m.exec(npmrc)[1]; return { electronVersion, msBuildId }; } -function acquireWebNodePaths() { - const root = path.join(__dirname, '..', '..'); - const webPackageJSON = path.join(root, '/remote/web', 'package.json'); - const webPackages = JSON.parse(fs.readFileSync(webPackageJSON, 'utf8')).dependencies; - const distroWebPackageJson = path.join(root, '.build/distro/npm/remote/web/package.json'); - if (fs.existsSync(distroWebPackageJson)) { - const distroWebPackages = JSON.parse(fs.readFileSync(distroWebPackageJson, 'utf8')).dependencies; - Object.assign(webPackages, distroWebPackages); - } - const nodePaths = {}; - for (const key of Object.keys(webPackages)) { - const packageJSON = path.join(root, 'node_modules', key, 'package.json'); - const packageData = JSON.parse(fs.readFileSync(packageJSON, 'utf8')); - // Only cases where the browser is a string are handled - let entryPoint = typeof packageData.browser === 'string' ? packageData.browser : packageData.main; - // On rare cases a package doesn't have an entrypoint so we assume it has a dist folder with a min.js - if (!entryPoint) { - // TODO @lramos15 remove this when jschardet adds an entrypoint so we can warn on all packages w/out entrypoint - if (key !== 'jschardet') { - console.warn(`No entry point for ${key} assuming dist/${key}.min.js`); - } - entryPoint = `dist/${key}.min.js`; - } - // Remove any starting path information so it's all relative info - if (entryPoint.startsWith('./')) { - entryPoint = entryPoint.substring(2); - } - else if (entryPoint.startsWith('/')) { - entryPoint = entryPoint.substring(1); - } - // Search for a minified entrypoint as well - if (/(? new Promise((resolve, _) => { - const root = path.join(__dirname, '..', '..'); - const nodePaths = acquireWebNodePaths(); - // Now we write the node paths to out/vs - const outDirectory = path.join(root, outDir, 'vs'); - fs.mkdirSync(outDirectory, { recursive: true }); - const headerWithGeneratedFileWarning = `/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - - // This file is generated by build/npm/postinstall.js. Do not edit.`; - const fileContents = `${headerWithGeneratedFileWarning}\nself.webPackagePaths = ${JSON.stringify(nodePaths, null, 2)};`; - fs.writeFileSync(path.join(outDirectory, 'webPackagePaths.js'), fileContents, 'utf8'); - resolve(); - }); - result.taskName = 'build-web-node-paths'; - return result; -} //# sourceMappingURL=util.js.map \ No newline at end of file diff --git a/build/lib/util.ts b/build/lib/util.ts index 4cbe8f552ceb8..08921834676de 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -367,16 +367,6 @@ export function filter(fn: (data: any) => boolean): FilterStream { return result; } -export function versionStringToNumber(versionStr: string) { - const semverRegex = /(\d+)\.(\d+)\.(\d+)/; - const match = versionStr.match(semverRegex); - if (!match) { - throw new Error('Version string is not properly formatted: ' + versionStr); - } - - return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10); -} - export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise { return new Promise((c, e) => { stream.on('error', err => e(err)); @@ -390,104 +380,3 @@ export function getElectronVersion(): Record { const msBuildId = /^ms_build_id="(.*)"$/m.exec(npmrc)![1]; return { electronVersion, msBuildId }; } - -export function acquireWebNodePaths() { - const root = path.join(__dirname, '..', '..'); - const webPackageJSON = path.join(root, '/remote/web', 'package.json'); - const webPackages = JSON.parse(fs.readFileSync(webPackageJSON, 'utf8')).dependencies; - - const distroWebPackageJson = path.join(root, '.build/distro/npm/remote/web/package.json'); - if (fs.existsSync(distroWebPackageJson)) { - const distroWebPackages = JSON.parse(fs.readFileSync(distroWebPackageJson, 'utf8')).dependencies; - Object.assign(webPackages, distroWebPackages); - } - - const nodePaths: { [key: string]: string } = {}; - for (const key of Object.keys(webPackages)) { - const packageJSON = path.join(root, 'node_modules', key, 'package.json'); - const packageData = JSON.parse(fs.readFileSync(packageJSON, 'utf8')); - // Only cases where the browser is a string are handled - let entryPoint: string = typeof packageData.browser === 'string' ? packageData.browser : packageData.main; - - // On rare cases a package doesn't have an entrypoint so we assume it has a dist folder with a min.js - if (!entryPoint) { - // TODO @lramos15 remove this when jschardet adds an entrypoint so we can warn on all packages w/out entrypoint - if (key !== 'jschardet') { - console.warn(`No entry point for ${key} assuming dist/${key}.min.js`); - } - - entryPoint = `dist/${key}.min.js`; - } - - // Remove any starting path information so it's all relative info - if (entryPoint.startsWith('./')) { - entryPoint = entryPoint.substring(2); - } else if (entryPoint.startsWith('/')) { - entryPoint = entryPoint.substring(1); - } - - // Search for a minified entrypoint as well - if (/(? new Promise((resolve, _) => { - const root = path.join(__dirname, '..', '..'); - const nodePaths = acquireWebNodePaths(); - // Now we write the node paths to out/vs - const outDirectory = path.join(root, outDir, 'vs'); - fs.mkdirSync(outDirectory, { recursive: true }); - const headerWithGeneratedFileWarning = `/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - - // This file is generated by build/npm/postinstall.js. Do not edit.`; - const fileContents = `${headerWithGeneratedFileWarning}\nself.webPackagePaths = ${JSON.stringify(nodePaths, null, 2)};`; - fs.writeFileSync(path.join(outDirectory, 'webPackagePaths.js'), fileContents, 'utf8'); - resolve(); - }); - result.taskName = 'build-web-node-paths'; - return result; -} diff --git a/build/linux/dependencies-generator.js b/build/linux/dependencies-generator.js index 5d4bb828382e1..eec4bd790cd59 100644 --- a/build/linux/dependencies-generator.js +++ b/build/linux/dependencies-generator.js @@ -15,7 +15,6 @@ const dep_lists_2 = require("./rpm/dep-lists"); const types_1 = require("./debian/types"); const types_2 = require("./rpm/types"); const product = require("../../product.json"); -const amd_1 = require("../lib/amd"); // 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 @@ -44,7 +43,7 @@ async function getDependencies(packageType, buildDir, applicationName, arch) { throw new Error('Invalid RPM arch string ' + arch); } // Get the files for which we want to find dependencies. - const canAsar = (0, amd_1.isAMD)(); // TODO@esm ASAR disabled in ESM + const canAsar = false; // TODO@esm ASAR disabled in ESM const nativeModulesPath = path.join(buildDir, 'resources', 'app', canAsar ? 'node_modules.asar.unpacked' : 'node_modules'); const findResult = (0, child_process_1.spawnSync)('find', [nativeModulesPath, '-name', '*.node']); if (findResult.status) { diff --git a/build/linux/dependencies-generator.ts b/build/linux/dependencies-generator.ts index d390818dc54a7..7faae4ba1049e 100644 --- a/build/linux/dependencies-generator.ts +++ b/build/linux/dependencies-generator.ts @@ -15,7 +15,6 @@ import { referenceGeneratedDepsByArch as rpmGeneratedDeps } from './rpm/dep-list import { DebianArchString, isDebianArchString } from './debian/types'; import { isRpmArchString, RpmArchString } from './rpm/types'; import product = require('../../product.json'); -import { isAMD } from '../lib/amd'; // A flag that can easily be toggled. // Make sure to compile the build directory after toggling the value. @@ -48,7 +47,7 @@ export async function getDependencies(packageType: 'deb' | 'rpm', buildDir: stri } // Get the files for which we want to find dependencies. - const canAsar = isAMD(); // TODO@esm ASAR disabled in ESM + const canAsar = false; // TODO@esm ASAR disabled in ESM const nativeModulesPath = path.join(buildDir, 'resources', 'app', canAsar ? 'node_modules.asar.unpacked' : 'node_modules'); const findResult = spawnSync('find', [nativeModulesPath, '-name', '*.node']); if (findResult.status) { diff --git a/extensions/fsharp/cgmanifest.json b/extensions/fsharp/cgmanifest.json index ba75f69541e84..75e24896d8e8c 100644 --- a/extensions/fsharp/cgmanifest.json +++ b/extensions/fsharp/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "ionide/ionide-fsgrammar", "repositoryUrl": "https://github.com/ionide/ionide-fsgrammar", - "commitHash": "b38420f8569aa662b4862beb407a02e527e866c1" + "commitHash": "c62c78404d0b2c14816aae61ac0688663a5990a3" } }, "license": "MIT", diff --git a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json index 9594d1b6ce8d1..8ba555b77727a 100644 --- a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json +++ b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/ionide/ionide-fsgrammar/commit/b38420f8569aa662b4862beb407a02e527e866c1", + "version": "https://github.com/ionide/ionide-fsgrammar/commit/c62c78404d0b2c14816aae61ac0688663a5990a3", "name": "fsharp", "scopeName": "source.fsharp", "patterns": [ @@ -635,7 +635,7 @@ }, "abstract_definition": { "name": "abstract.definition.fsharp", - "begin": "\\b(static)?\\s+(abstract)\\s+(member)?(\\s+\\[\\<.*\\>\\])?\\s*([_[:alpha:]0-9,\\._`\\s]+)(<)?", + "begin": "\\b(static\\s+)?(abstract)\\s+(member)?(\\s+\\[\\<.*\\>\\])?\\s*([_[:alpha:]0-9,\\._`\\s]+)(<)?", "end": "\\s*(with)\\b|=|$", "beginCaptures": { "1": { diff --git a/extensions/git/src/actionButton.ts b/extensions/git/src/actionButton.ts index 494972276ac0e..2fbdaf4f97ebc 100644 --- a/extensions/git/src/actionButton.ts +++ b/extensions/git/src/actionButton.ts @@ -211,12 +211,12 @@ export class ActionButton { command: { command: 'git.sync', title: l10n.t('{0} Sync Changes{1}{2}', icon, behind, ahead), + shortTitle: `${icon}${behind}${ahead}`, tooltip: this.state.isSyncInProgress ? l10n.t('Synchronizing Changes...') : this.repository.syncTooltip, arguments: [this.repository.sourceControl], }, - description: `${icon}${behind}${ahead}`, enabled: !this.state.isCheckoutInProgress && !this.state.isSyncInProgress }; } diff --git a/extensions/git/src/test/smoke.test.ts b/extensions/git/src/test/smoke.test.ts index 1b2c8c259baf1..173364c7f099d 100644 --- a/extensions/git/src/test/smoke.test.ts +++ b/extensions/git/src/test/smoke.test.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as assert from 'assert'; -import { workspace, commands, window, Uri, WorkspaceEdit, Range, TextDocument, extensions } from 'vscode'; +import { workspace, commands, window, Uri, WorkspaceEdit, Range, TextDocument, extensions, TabInputTextDiff } from 'vscode'; import * as cp from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; @@ -73,17 +73,22 @@ suite('git smoke test', function () { await type(appjs, ' world'); await appjs.save(); await repository.status(); + assert.strictEqual(repository.state.workingTreeChanges.length, 1); - repository.state.workingTreeChanges.some(r => r.uri.path === appjs.uri.path && r.status === Status.MODIFIED); + assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, appjs.uri.path); + assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.MODIFIED); fs.writeFileSync(file('newfile.txt'), ''); const newfile = await open('newfile.txt'); await type(newfile, 'hey there'); await newfile.save(); await repository.status(); + assert.strictEqual(repository.state.workingTreeChanges.length, 2); - repository.state.workingTreeChanges.some(r => r.uri.path === appjs.uri.path && r.status === Status.MODIFIED); - repository.state.workingTreeChanges.some(r => r.uri.path === newfile.uri.path && r.status === Status.UNTRACKED); + assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, appjs.uri.path); + assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.MODIFIED); + assert.strictEqual(repository.state.workingTreeChanges[1].uri.path, newfile.uri.path); + assert.strictEqual(repository.state.workingTreeChanges[1].status, Status.UNTRACKED); }); test('opens diff editor', async function () { @@ -93,37 +98,50 @@ suite('git smoke test', function () { assert(window.activeTextEditor); assert.strictEqual(window.activeTextEditor!.document.uri.path, appjs.path); - // TODO: how do we really know this is a diff editor? + assert(window.tabGroups.activeTabGroup.activeTab); + assert(window.tabGroups.activeTabGroup.activeTab!.input instanceof TabInputTextDiff); }); test('stages correctly', async function () { const appjs = uri('app.js'); const newfile = uri('newfile.txt'); - await commands.executeCommand('git.stage', appjs); - assert.strictEqual(repository.state.workingTreeChanges.length, 1); - repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED); + await repository.add([appjs.fsPath]); + assert.strictEqual(repository.state.indexChanges.length, 1); - repository.state.indexChanges.some(r => r.uri.path === appjs.path && r.status === Status.INDEX_MODIFIED); + assert.strictEqual(repository.state.indexChanges[0].uri.path, appjs.path); + assert.strictEqual(repository.state.indexChanges[0].status, Status.INDEX_MODIFIED); + + assert.strictEqual(repository.state.workingTreeChanges.length, 1); + assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, newfile.path); + assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.UNTRACKED); + + await repository.revert([appjs.fsPath]); + + assert.strictEqual(repository.state.indexChanges.length, 0); - await commands.executeCommand('git.unstage', appjs); assert.strictEqual(repository.state.workingTreeChanges.length, 2); - repository.state.workingTreeChanges.some(r => r.uri.path === appjs.path && r.status === Status.MODIFIED); - repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED); + assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, appjs.path); + assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.MODIFIED); + assert.strictEqual(repository.state.workingTreeChanges[1].uri.path, newfile.path); + assert.strictEqual(repository.state.workingTreeChanges[1].status, Status.UNTRACKED); }); test('stages, commits changes and verifies outgoing change', async function () { const appjs = uri('app.js'); const newfile = uri('newfile.txt'); - await commands.executeCommand('git.stage', appjs); + await repository.add([appjs.fsPath]); await repository.commit('second commit'); + assert.strictEqual(repository.state.workingTreeChanges.length, 1); - repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED); + assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, newfile.path); + assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.UNTRACKED); + assert.strictEqual(repository.state.indexChanges.length, 0); - await commands.executeCommand('git.stageAll', appjs); - await repository.commit('third commit'); + await repository.commit('third commit', { all: true }); + assert.strictEqual(repository.state.workingTreeChanges.length, 0); assert.strictEqual(repository.state.indexChanges.length, 0); }); @@ -131,16 +149,19 @@ suite('git smoke test', function () { test('rename/delete conflict', async function () { await commands.executeCommand('workbench.view.scm'); + const appjs = file('app.js'); + const renamejs = file('rename.js'); + await repository.createBranch('test', true); // Delete file (test branch) - fs.unlinkSync(file('app.js')); + fs.unlinkSync(appjs); await repository.commit('commit on test', { all: true }); await repository.checkout('main'); // Rename file (main branch) - fs.renameSync(file('app.js'), file('rename.js')); + fs.renameSync(appjs, renamejs); await repository.commit('commit on main', { all: true }); try { @@ -148,6 +169,8 @@ suite('git smoke test', function () { } catch (e) { } assert.strictEqual(repository.state.mergeChanges.length, 1); + assert.strictEqual(repository.state.mergeChanges[0].status, Status.DELETED_BY_THEM); + assert.strictEqual(repository.state.workingTreeChanges.length, 0); assert.strictEqual(repository.state.indexChanges.length, 0); }); diff --git a/extensions/go/cgmanifest.json b/extensions/go/cgmanifest.json index 39db8ac979f61..ae7228fa1aea4 100644 --- a/extensions/go/cgmanifest.json +++ b/extensions/go/cgmanifest.json @@ -6,12 +6,12 @@ "git": { "name": "go-syntax", "repositoryUrl": "https://github.com/worlpaker/go-syntax", - "commitHash": "b40fb01f2cf48bc24e6f4030373311b0402b158e" + "commitHash": "ce0d1d19653dc264d8e53f97cb45cc8d1689f221" } }, "license": "MIT", "description": "The file syntaxes/go.tmLanguage.json is from https://github.com/worlpaker/go-syntax, which in turn was derived from https://github.com/jeff-hykin/better-go-syntax.", - "version": "0.7.6" + "version": "0.7.7" } ], "version": 1 diff --git a/extensions/go/syntaxes/go.tmLanguage.json b/extensions/go/syntaxes/go.tmLanguage.json index bc56a1b97eee6..8ae31fdbe31c0 100644 --- a/extensions/go/syntaxes/go.tmLanguage.json +++ b/extensions/go/syntaxes/go.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/worlpaker/go-syntax/commit/b40fb01f2cf48bc24e6f4030373311b0402b158e", + "version": "https://github.com/worlpaker/go-syntax/commit/ce0d1d19653dc264d8e53f97cb45cc8d1689f221", "name": "Go", "scopeName": "source.go", "patterns": [ @@ -2192,7 +2192,7 @@ ] } }, - "end": "(?:(?<=\\])((?:\\s+)(?:(?:(?:[\\*\\[\\]]+)?(?:\\<\\-\\s*)?\\bchan\\b(?:\\s*\\<\\-)?\\s*)+)?(?:(?!(?:[\\[\\]\\*]+)?(?:\\bstruct\\b|\\binterface\\b|\\bfunc\\b))[\\w\\.\\-\\*\\[\\]]+(?:\\,\\s+[\\w\\.\\[\\]\\*]+)*))?)", + "end": "(?:(?<=\\])((?:\\s+)(?:\\=\\s*)?(?:(?:(?:[\\*\\[\\]]+)?(?:\\<\\-\\s*)?\\bchan\\b(?:\\s*\\<\\-)?\\s*)+)?(?:(?!(?:[\\[\\]\\*]+)?(?:\\bstruct\\b|\\binterface\\b|\\bfunc\\b))[\\w\\.\\-\\*\\[\\]]+(?:\\,\\s*[\\w\\.\\[\\]\\*]+)*))?)", "endCaptures": { "1": { "patterns": [ diff --git a/extensions/latex/cgmanifest.json b/extensions/latex/cgmanifest.json index 3c7203d5d2a4b..609d875ac2faf 100644 --- a/extensions/latex/cgmanifest.json +++ b/extensions/latex/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "jlelong/vscode-latex-basics", "repositoryUrl": "https://github.com/jlelong/vscode-latex-basics", - "commitHash": "969429cb9230a63f9155987f069acd4234d10e1a" + "commitHash": "56e2dc967e6bafafc1acfeeb80af42b8328b021a" } }, "license": "MIT", - "version": "1.9.0", + "version": "1.7.0", "description": "The files in syntaxes/ were originally part of https://github.com/James-Yu/LaTeX-Workshop. They have been extracted in the hope that they can useful outside of the LaTeX-Workshop extension.", "licenseDetail": [ "Copyright (c) vscode-latex-basics authors", diff --git a/extensions/latex/syntaxes/LaTeX.tmLanguage.json b/extensions/latex/syntaxes/LaTeX.tmLanguage.json index bc97a73bda873..e06d855384648 100644 --- a/extensions/latex/syntaxes/LaTeX.tmLanguage.json +++ b/extensions/latex/syntaxes/LaTeX.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/jlelong/vscode-latex-basics/commit/969429cb9230a63f9155987f069acd4234d10e1a", + "version": "https://github.com/jlelong/vscode-latex-basics/commit/59971565a7065dbb617576c04add9d891b056319", "name": "LaTeX", "scopeName": "text.tex.latex", "patterns": [ @@ -2002,7 +2002,7 @@ ] } }, - "contentName": "punctuation.definition.comment.latex", + "contentName": "comment.line.percentage.latex", "end": "(\\\\end\\{\\2\\})", "name": "meta.function.verbatim.latex" }, diff --git a/extensions/latex/syntaxes/TeX.tmLanguage.json b/extensions/latex/syntaxes/TeX.tmLanguage.json index 0cb03e614665c..b3a328174820a 100644 --- a/extensions/latex/syntaxes/TeX.tmLanguage.json +++ b/extensions/latex/syntaxes/TeX.tmLanguage.json @@ -4,12 +4,12 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/jlelong/vscode-latex-basics/commit/5d7c2a4e451a932b776f6d9342087be6a1e8c0a1", + "version": "https://github.com/jlelong/vscode-latex-basics/commit/df6ef817c932d24da5cc72927344a547e463cc65", "name": "TeX", "scopeName": "text.tex", "patterns": [ { - "begin": "(?<=^\\s*)((\\\\)iffalse)", + "begin": "(?<=^\\s*)((\\\\)iffalse)(?!\\s*[{}]\\s*\\\\fi)", "beginCaptures": { "1": { "name": "keyword.control.tex" @@ -19,7 +19,7 @@ } }, "contentName": "comment.line.percentage.tex", - "end": "(?<=^\\s*)((\\\\)(?:else|fi))", + "end": "((\\\\)(?:else|fi))", "endCaptures": { "1": { "name": "keyword.control.tex" @@ -32,6 +32,9 @@ { "include": "#comment" }, + { + "include": "#braces" + }, { "include": "#conditionals" } diff --git a/extensions/perl/cgmanifest.json b/extensions/perl/cgmanifest.json index cd175abe37de7..b7c850dd1aab8 100644 --- a/extensions/perl/cgmanifest.json +++ b/extensions/perl/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "textmate/perl.tmbundle", "repositoryUrl": "https://github.com/textmate/perl.tmbundle", - "commitHash": "a85927a902d6e5d7805f56a653f324d34dfad53a" + "commitHash": "d9841a0878239fa43f88c640f8d458590f97e8f5" } }, "licenseDetail": [ diff --git a/extensions/postinstall.mjs b/extensions/postinstall.mjs index 04e54dd6e2cab..f073aa720c91f 100644 --- a/extensions/postinstall.mjs +++ b/extensions/postinstall.mjs @@ -26,7 +26,10 @@ function processRoot() { function processLib() { const toDelete = new Set([ 'tsc.js', + '_tsc.js', + 'typescriptServices.js', + '_typescriptServices.js', ]); const libRoot = path.join(root, 'lib'); diff --git a/extensions/r/cgmanifest.json b/extensions/r/cgmanifest.json index b1ccd271d8180..7f012c6076e5c 100644 --- a/extensions/r/cgmanifest.json +++ b/extensions/r/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "REditorSupport/vscode-R", "repositoryUrl": "https://github.com/REditorSupport/vscode-R", - "commitHash": "ad966f3b2de8a83594f90aa5b51f5b569cf02c08" + "commitHash": "c937cdd39982995d8ee1f1125919f7c2d150b35d" } }, "license": "MIT", - "version": "2.8.1" + "version": "2.8.4" } ], "version": 1 diff --git a/extensions/r/syntaxes/r.tmLanguage.json b/extensions/r/syntaxes/r.tmLanguage.json index d50ab5b6d78f3..dcdc9622bf767 100644 --- a/extensions/r/syntaxes/r.tmLanguage.json +++ b/extensions/r/syntaxes/r.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/REditorSupport/vscode-R/commit/ad966f3b2de8a83594f90aa5b51f5b569cf02c08", + "version": "https://github.com/REditorSupport/vscode-R/commit/c937cdd39982995d8ee1f1125919f7c2d150b35d", "name": "R", "scopeName": "source.r", "patterns": [ @@ -158,14 +158,6 @@ { "match": "\\b([[:alnum:]_]+)(?=::)", "name": "entity.namespace.r" - }, - { - "match": "\\b([[:alnum:]._]+)\\b", - "name": "variable.other.r" - }, - { - "match": "(`[^`]+`)", - "name": "variable.other.r" } ] }, diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index d9c4ddb2a65b8..21506b11ede96 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -236,7 +236,7 @@ "configuration.tsserver.web.projectWideIntellisense.suppressSemanticErrors": "Suppresses semantic errors on web even when project wide IntelliSense is enabled. This is always on when project wide IntelliSense is not enabled or available. See `#typescript.tsserver.web.projectWideIntellisense.enabled#`", "configuration.tsserver.web.typeAcquisition.enabled": "Enable/disable package acquisition on the web. This enables IntelliSense for imported packages. Requires `#typescript.tsserver.web.projectWideIntellisense.enabled#`. Currently not supported for Safari.", "configuration.tsserver.nodePath": "Run TS Server on a custom Node installation. This can be a path to a Node executable, or 'node' if you want VS Code to detect a Node installation.", - "configuration.updateImportsOnPaste": "Automatically update imports when pasting code. Requires TypeScript 5.6+.", + "configuration.updateImportsOnPaste": "Automatically update imports when pasting code. Requires TypeScript 5.7+.", "configuration.expandableHover": "(Experimental) Enable/disable expanding on hover.", "walkthroughs.nodejsWelcome.title": "Get started with JavaScript and Node.js", "walkthroughs.nodejsWelcome.description": "Make the most of Visual Studio Code's first-class JavaScript experience.", diff --git a/extensions/typescript-language-features/src/languageFeatures/copyPaste.ts b/extensions/typescript-language-features/src/languageFeatures/copyPaste.ts index 3e2e61a8a52c3..debf060d0ea58 100644 --- a/extensions/typescript-language-features/src/languageFeatures/copyPaste.ts +++ b/extensions/typescript-language-features/src/languageFeatures/copyPaste.ts @@ -50,7 +50,24 @@ class DocumentPasteProvider implements vscode.DocumentPasteEditProvider { private readonly _client: ITypeScriptServiceClient, ) { } - prepareDocumentPaste(document: vscode.TextDocument, ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken) { + async prepareDocumentPaste(document: vscode.TextDocument, ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken) { + if (!this.isEnabled(document)) { + return; + } + + const file = this._client.toOpenTsFilePath(document); + if (!file) { + return; + } + + const response = await this._client.execute('preparePasteEdits', { + file, + copiedTextSpan: ranges.map(typeConverters.Range.toTextSpan), + }, token); + if (token.isCancellationRequested || response.type !== 'response' || !response.body) { + return; + } + dataTransfer.set(DocumentPasteProvider.metadataMimeType, new vscode.DataTransferItem(new CopyMetadata(document.uri, ranges).toJSON())); } @@ -62,8 +79,7 @@ class DocumentPasteProvider implements vscode.DocumentPasteEditProvider { _context: vscode.DocumentPasteEditContext, token: vscode.CancellationToken, ): Promise { - const config = vscode.workspace.getConfiguration(this._modeId, document.uri); - if (!config.get(settingId, false)) { + if (!this.isEnabled(document)) { return; } @@ -127,12 +143,17 @@ class DocumentPasteProvider implements vscode.DocumentPasteEditProvider { return metadata ? CopyMetadata.fromJSON(metadata) : undefined; } + + private isEnabled(document: vscode.TextDocument) { + const config = vscode.workspace.getConfiguration(this._modeId, document.uri); + return config.get(settingId, false); + } } export function register(selector: DocumentSelector, language: LanguageDescription, client: ITypeScriptServiceClient) { return conditionalRegistration([ requireSomeCapability(client, ClientCapability.Semantic), - requireMinVersion(client, API.v560), + requireMinVersion(client, API.v570), requireGlobalConfiguration(language.id, settingId), ], () => { return vscode.languages.registerDocumentPasteEditProvider(selector.semantic, new DocumentPasteProvider(language.id, client), { diff --git a/extensions/typescript-language-features/src/tsServer/api.ts b/extensions/typescript-language-features/src/tsServer/api.ts index 7b6d160952ee2..4ddc29944f0a4 100644 --- a/extensions/typescript-language-features/src/tsServer/api.ts +++ b/extensions/typescript-language-features/src/tsServer/api.ts @@ -28,7 +28,6 @@ export class API { public static readonly v520 = API.fromSimpleString('5.2.0'); public static readonly v544 = API.fromSimpleString('5.4.4'); public static readonly v540 = API.fromSimpleString('5.4.0'); - public static readonly v550 = API.fromSimpleString('5.5.0'); public static readonly v560 = API.fromSimpleString('5.6.0'); public static readonly v570 = API.fromSimpleString('5.7.0'); diff --git a/extensions/typescript-language-features/src/tsServer/protocol/protocol.d.ts b/extensions/typescript-language-features/src/tsServer/protocol/protocol.d.ts index 747e7c22e3724..cd70b6b7d41c3 100644 --- a/extensions/typescript-language-features/src/tsServer/protocol/protocol.d.ts +++ b/extensions/typescript-language-features/src/tsServer/protocol/protocol.d.ts @@ -19,5 +19,18 @@ declare module '../../../../node_modules/typescript/lib/typescript' { interface Response { readonly _serverType?: ServerType; } + + //#region PreparePasteEdits + interface PreparePasteEditsRequest extends FileRequest { + command: 'preparePasteEdits'; + arguments: PreparePasteEditsRequestArgs; + } + interface PreparePasteEditsRequestArgs extends FileRequestArgs { + copiedTextSpan: TextSpan[]; + } + interface PreparePasteEditsResponse extends Response { + body: boolean; + } + //#endregion } } diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index 931b287df03e1..90528ee47dc8c 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -78,6 +78,7 @@ interface StandardTsServerRequests { 'linkedEditingRange': [Proto.FileLocationRequestArgs, Proto.LinkedEditingRangeResponse]; 'mapCode': [Proto.MapCodeRequestArgs, Proto.MapCodeResponse]; 'getPasteEdits': [Proto.GetPasteEditsRequestArgs, Proto.GetPasteEditsResponse]; + 'preparePasteEdits': [Proto.PreparePasteEditsRequestArgs, Proto.PreparePasteEditsResponse]; } interface NoResponseTsServerRequests { diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_r.json b/extensions/vscode-colorize-tests/test/colorize-results/test_r.json index 128918635b56d..44936307a051d 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_r.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_r.json @@ -476,21 +476,7 @@ } }, { - "c": "x", - "t": "source.r variable.other.r", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "dark_modern": "variable: #9CDCFE", - "hc_light": "variable: #001080", - "light_modern": "variable: #001080" - } - }, - { - "c": ", ", + "c": "x, y", "t": "source.r", "r": { "dark_plus": "default: #D4D4D4", @@ -503,20 +489,6 @@ "light_modern": "default: #3B3B3B" } }, - { - "c": "y", - "t": "source.r variable.other.r", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "dark_modern": "variable: #9CDCFE", - "hc_light": "variable: #001080", - "light_modern": "variable: #001080" - } - }, { "c": ")", "t": "source.r punctuation.section.parens.end.r", @@ -560,35 +532,7 @@ } }, { - "c": " ", - "t": "source.r", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "dark_modern": "default: #CCCCCC", - "hc_light": "default: #292929", - "light_modern": "default: #3B3B3B" - } - }, - { - "c": "x", - "t": "source.r variable.other.r", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "dark_modern": "variable: #9CDCFE", - "hc_light": "variable: #001080", - "light_modern": "variable: #001080" - } - }, - { - "c": " ", + "c": " x ", "t": "source.r", "r": { "dark_plus": "default: #D4D4D4", @@ -616,7 +560,7 @@ } }, { - "c": " ", + "c": " y", "t": "source.r", "r": { "dark_plus": "default: #D4D4D4", @@ -629,20 +573,6 @@ "light_modern": "default: #3B3B3B" } }, - { - "c": "y", - "t": "source.r variable.other.r", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "dark_modern": "variable: #9CDCFE", - "hc_light": "variable: #001080", - "light_modern": "variable: #001080" - } - }, { "c": "}", "t": "source.r punctuation.section.braces.end.r", diff --git a/migrate.mjs b/migrate.mjs deleted file mode 100644 index ef8a8346169aa..0000000000000 --- a/migrate.mjs +++ /dev/null @@ -1,364 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check - -// ***************************************************************** -// * * -// * AMD-TO-ESM MIGRATION SCRIPT * -// * * -// ***************************************************************** - -import { readFileSync, writeFileSync, unlinkSync } from 'node:fs'; -import { join, extname, dirname, relative } from 'node:path'; -import { preProcessFile } from 'typescript'; -import { existsSync, mkdirSync, readdirSync, statSync } from 'fs'; -import { fileURLToPath } from 'node:url'; - -// @ts-expect-error -import watch from './build/lib/watch/index.js'; - -const enableWatching = !process.argv.includes('--disable-watch'); -const enableInPlace = process.argv.includes('--enable-in-place'); -const esmToAmd = process.argv.includes('--enable-esm-to-amd'); -const amdToEsm = !esmToAmd; - -const srcFolder = fileURLToPath(new URL('src', import.meta.url)); -const dstFolder = fileURLToPath(new URL(enableInPlace ? 'src' : 'src2', import.meta.url)); - -const binaryFileExtensions = new Set([ - '.svg', '.ttf', '.png', '.sh', '.html', '.json', '.zsh', '.scpt', '.mp3', '.fish', '.ps1', '.psm1', '.md', '.txt', '.zip', '.pdf', '.qwoff', '.jxs', '.tst', '.wuff', '.less', '.utf16le', '.snap', '.actual', '.tsx', '.scm' -]); - -function migrate() { - console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`); - console.log(`STARTING ${amdToEsm ? 'AMD->ESM' : 'ESM->AMD'} MIGRATION of ${enableInPlace ? 'src in-place' : 'src to src2'}.`); - - // installing watcher quickly to avoid missing early events - const watchSrc = enableWatching ? watch('src/**', { base: 'src', readDelay: 200 }) : undefined; - - /** @type {string[]} */ - const files = []; - readdir(srcFolder, files); - - for (const filePath of files) { - const fileContents = readFileSync(filePath); - migrateOne(filePath, fileContents); - } - - if (amdToEsm) { - writeFileSync(join(dstFolder, 'package.json'), `{"type": "module"}`); - } else { - unlinkSync(join(dstFolder, 'package.json')); - } - - if (!enableInPlace) { - writeFileSync(join(dstFolder, '.gitignore'), `*`); - } - - console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`); - console.log(`COMPLETED ${amdToEsm ? 'AMD->ESM' : 'ESM->AMD'} MIGRATION of ${enableInPlace ? 'src in-place' : 'src to src2'}. You can now launch npm run watch-amd or npm run watch-client-amd`); - if (esmToAmd) { - console.log(`Make sure to set the environment variable VSCODE_BUILD_AMD to a string of value 'true' if you want to build VS Code as AMD`); - } - - if (watchSrc) { - console.log(`WATCHING src for changes...`); - - watchSrc.on('data', (e) => { - migrateOne(e.path, e.contents); - console.log(`Handled change event for ${e.path}.`); - }); - } -} - -/** - * @param filePath - * @param fileContents - */ -function migrateOne(filePath, fileContents) { - const fileExtension = extname(filePath); - - if (fileExtension === '.ts') { - migrateTS(filePath, fileContents.toString()); - } else if (filePath.endsWith('tsconfig.base.json')) { - const opts = JSON.parse(fileContents.toString()); - if (amdToEsm) { - opts.compilerOptions.module = 'es2022'; - opts.compilerOptions.allowSyntheticDefaultImports = true; - } else { - opts.compilerOptions.module = 'amd'; - delete opts.compilerOptions.allowSyntheticDefaultImports; - } - writeDestFile(filePath, JSON.stringify(opts, null, '\t')); - } else if (fileExtension === '.js' || fileExtension === '.cjs' || fileExtension === '.mjs' || fileExtension === '.css' || binaryFileExtensions.has(fileExtension)) { - writeDestFile(filePath, fileContents); - } else { - console.log(`ignoring ${filePath}`); - } -} - -/** - * @param fileContents - * @typedef {{pos:number;end:number;}} Import - * @return - */ -function discoverImports(fileContents) { - const info = preProcessFile(fileContents); - const search = /export .* from ['"]([^'"]+)['"]/g; - /** typedef {Import[]} */ - let result = []; - do { - const m = search.exec(fileContents); - if (!m) { - break; - } - const end = m.index + m[0].length - 2; - const pos = end - m[1].length; - result.push({ pos, end }); - } while (true); - - result = result.concat(info.importedFiles); - - result.sort((a, b) => { - return a.pos - b.pos; - }); - for (let i = 1; i < result.length; i++) { - const prev = result[i - 1]; - const curr = result[i]; - if (prev.pos === curr.pos) { - result.splice(i, 1); - i--; - } - } - return result; -} - -/** - * @param filePath - * @param fileContents - */ -function migrateTS(filePath, fileContents) { - if (filePath.endsWith('.d.ts')) { - return writeDestFile(filePath, fileContents); - } - - const imports = discoverImports(fileContents); - /** @type {Replacement[]} */ - const replacements = []; - for (let i = imports.length - 1; i >= 0; i--) { - const pos = imports[i].pos + 1; - const end = imports[i].end + 1; - const importedFilename = fileContents.substring(pos, end); - - /** @type {string|undefined} */ - let importedFilepath = undefined; - if (amdToEsm) { - if (/^vs\/css!/.test(importedFilename)) { - importedFilepath = importedFilename.substr('vs/css!'.length) + '.css'; - } else { - importedFilepath = importedFilename; - } - } else { - if (importedFilename.endsWith('.css')) { - importedFilepath = `vs/css!${importedFilename.substr(0, importedFilename.length - 4)}`; - } else if (importedFilename.endsWith('.js')) { - importedFilepath = importedFilename.substr(0, importedFilename.length - 3); - } - } - - if (typeof importedFilepath !== 'string') { - continue; - } - - /** @type {boolean} */ - let isRelativeImport; - if (amdToEsm) { - if (/(^\.\/)|(^\.\.\/)/.test(importedFilepath)) { - importedFilepath = join(dirname(filePath), importedFilepath); - isRelativeImport = true; - } else if (/^vs\//.test(importedFilepath)) { - importedFilepath = join(srcFolder, importedFilepath); - isRelativeImport = true; - } else { - importedFilepath = importedFilepath; - isRelativeImport = false; - } - } else { - importedFilepath = importedFilepath; - isRelativeImport = false; - } - - /** @type {string} */ - let replacementImport; - - if (isRelativeImport) { - replacementImport = generateRelativeImport(filePath, importedFilepath); - } else { - replacementImport = importedFilepath; - } - - replacements.push({ pos, end, text: replacementImport }); - } - - fileContents = applyReplacements(fileContents, replacements); - - writeDestFile(filePath, fileContents); -} - -/** - * @param filePath - * @param importedFilepath - */ -function generateRelativeImport(filePath, importedFilepath) { - /** @type {string} */ - let relativePath; - // See https://github.com/microsoft/TypeScript/issues/16577#issuecomment-754941937 - if (!importedFilepath.endsWith('.css') && !importedFilepath.endsWith('.cjs')) { - importedFilepath = `${importedFilepath}.js`; - } - relativePath = relative(dirname(filePath), `${importedFilepath}`); - relativePath = relativePath.replace(/\\/g, '/'); - if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) { - relativePath = './' + relativePath; - } - return relativePath; -} - -/** @typedef {{pos:number;end:number;text:string;}} Replacement */ - -/** - * @param str - * @param replacements - */ -function applyReplacements(str, replacements) { - replacements.sort((a, b) => { - return a.pos - b.pos; - }); - - /** @type {string[]} */ - const result = []; - let lastEnd = 0; - for (const replacement of replacements) { - const { pos, end, text } = replacement; - result.push(str.substring(lastEnd, pos)); - result.push(text); - lastEnd = end; - } - result.push(str.substring(lastEnd, str.length)); - return result.join(''); -} - -/** - * @param srcFilePath - * @param fileContents - */ -function writeDestFile(srcFilePath, fileContents) { - const destFilePath = srcFilePath.replace(srcFolder, dstFolder); - ensureDir(dirname(destFilePath)); - - if (/(\.ts$)|(\.js$)|(\.html$)/.test(destFilePath)) { - fileContents = toggleComments(fileContents); - } - - /** @type {Buffer | undefined} */ - let existingFileContents = undefined; - try { - existingFileContents = readFileSync(destFilePath); - } catch (err) { } - if (!buffersAreEqual(existingFileContents, fileContents)) { - writeFileSync(destFilePath, fileContents); - } - - /** - * @param fileContents - */ - function toggleComments(fileContents) { - const lines = String(fileContents).split(/\r\n|\r|\n/); - let mode = 0; - let didChange = false; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (mode === 0) { - if (amdToEsm ? /\/\/ ESM-comment-begin/.test(line) : /\/\/ ESM-uncomment-begin/.test(line)) { - mode = 1; - continue; - } - if (amdToEsm ? /\/\/ ESM-uncomment-begin/.test(line) : /\/\/ ESM-comment-begin/.test(line)) { - mode = 2; - continue; - } - continue; - } - - if (mode === 1) { - if (amdToEsm ? /\/\/ ESM-comment-end/.test(line) : /\/\/ ESM-uncomment-end/.test(line)) { - mode = 0; - continue; - } - didChange = true; - lines[i] = line.replace(/^\s*/, (match) => match + '// '); - continue; - } - - if (mode === 2) { - if (amdToEsm ? /\/\/ ESM-uncomment-end/.test(line) : /\/\/ ESM-comment-end/.test(line)) { - mode = 0; - continue; - } - didChange = true; - lines[i] = line.replace(/^(\s*)\/\/ ?/, function (_, indent) { - return indent; - }); - } - } - - if (didChange) { - return lines.join('\n'); - } - return fileContents; - } -} - -/** - * @param existingFileContents - * @param fileContents - */ -function buffersAreEqual(existingFileContents, fileContents) { - if (!existingFileContents) { - return false; - } - if (typeof fileContents === 'string') { - fileContents = Buffer.from(fileContents); - } - return existingFileContents.equals(fileContents); -} - -const ensureDirCache = new Set(); -function ensureDir(dirPath) { - if (ensureDirCache.has(dirPath)) { - return; - } - ensureDirCache.add(dirPath); - ensureDir(dirname(dirPath)); - if (!existsSync(dirPath)) { - mkdirSync(dirPath); - } -} - -function readdir(dirPath, result) { - const entries = readdirSync(dirPath); - for (const entry of entries) { - const entryPath = join(dirPath, entry); - const stat = statSync(entryPath); - if (stat.isDirectory()) { - readdir(join(dirPath, entry), result); - } else { - result.push(entryPath); - } - } -} - -migrate(); diff --git a/package-lock.json b/package-lock.json index 9b1e05da4fe0f..114cfbd760420 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,14 +26,14 @@ "@vscode/windows-mutex": "^0.5.0", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "^0.2.0-beta.47", - "@xterm/addon-image": "^0.9.0-beta.64", - "@xterm/addon-search": "^0.16.0-beta.64", - "@xterm/addon-serialize": "^0.14.0-beta.64", - "@xterm/addon-unicode11": "^0.9.0-beta.64", - "@xterm/addon-webgl": "^0.19.0-beta.64", - "@xterm/headless": "^5.6.0-beta.64", - "@xterm/xterm": "^5.6.0-beta.64", + "@xterm/addon-clipboard": "^0.2.0-beta.48", + "@xterm/addon-image": "^0.9.0-beta.65", + "@xterm/addon-search": "^0.16.0-beta.65", + "@xterm/addon-serialize": "^0.14.0-beta.65", + "@xterm/addon-unicode11": "^0.9.0-beta.65", + "@xterm/addon-webgl": "^0.19.0-beta.65", + "@xterm/headless": "^5.6.0-beta.65", + "@xterm/xterm": "^5.6.0-beta.65", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.3", @@ -42,7 +42,7 @@ "native-is-elevated": "0.7.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta21", + "node-pty": "^1.1.0-beta22", "open": "^8.4.2", "tas-client-umd": "0.2.0", "v8-inspect-profiler": "^0.1.1", @@ -154,7 +154,7 @@ "ts-node": "^10.9.1", "tsec": "0.2.7", "tslib": "^2.6.3", - "typescript": "^5.7.0-dev.20240903", + "typescript": "^5.7.0-dev.20240927", "util": "^0.12.4", "webpack": "^5.94.0", "webpack-cli": "^5.1.4", @@ -3505,65 +3505,65 @@ } }, "node_modules/@xterm/addon-clipboard": { - "version": "0.2.0-beta.47", - "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.47.tgz", - "integrity": "sha512-mJHV1770gwVckj4mgjdxegt4zLL5WGCoJblTqaLbgEF7xOwsJUzvGk38qsZ4ZpdTa2ti76H0pkb1CpZGrXL9qg==", + "version": "0.2.0-beta.48", + "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.48.tgz", + "integrity": "sha512-oTrGoGMOQaW7PINAShhNR3duV8l2No/DbJ9rtfSBjfoQ9clWe0K+4fUHdJIuzW65AZsiLo9oh5IbHLWxlFP3Jg==", "dependencies": { "js-base64": "^3.7.5" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-image": { - "version": "0.9.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.64.tgz", - "integrity": "sha512-1Aqqytx/z/Khecf5xrO++f/p5EQX4uG87TbbAmE0OQys/JgKMnNggDzqon5bpHboimLfQiFPw716NbTqMphjfw==", + "version": "0.9.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.65.tgz", + "integrity": "sha512-Ud5FI5cGtpbz8yYCHC4QINlbC1K04Mex1JD5oAWPFwjlOz/Si/DhqbY1QBDl6QrUmSUUTZc5DKT3v3nN5WbZxQ==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-search": { - "version": "0.16.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.64.tgz", - "integrity": "sha512-vUsvTkEOFJwv8nVtiiGr/vTMeQhu62VkUejY2h1+yZagnVEusGVPU1JYoqBTLu5HM4cFiTGsJYXFI/0apASXYA==", + "version": "0.16.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.65.tgz", + "integrity": "sha512-eHfbbgFCS3AcD8YSvGFIkW9NW4pfGHrtRDWIojM/zqmyi3JaCmHUgZmlxbaANwBlgLiNpJLDq7cmoz//86NgGw==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-serialize": { - "version": "0.14.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.64.tgz", - "integrity": "sha512-0AqVveTV3Pr9Lp+beJYOP5WuRvIrPSDGAK24da7BRGcLIKVq8pok1FdlM9jPeUbkX0DKo6Ortm77qeb2Z+n8+A==", + "version": "0.14.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.65.tgz", + "integrity": "sha512-NlvXVtFAHpLKEDzd+6/68yPFQ4Oe02jvQH6+a8p+gcxbSEyYj1l0sqqeABQ3gC5QDCmQepk6BQVB8Rpz/e4HgQ==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-unicode11": { - "version": "0.9.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.64.tgz", - "integrity": "sha512-3+PKu+DXFq32xlsYfnI058/T8dTY2tQhRpJLP2CNR/jVWk5uBkVO0dBV0Srqj5QOAlAhzzZuS6TbsVRXORptqw==", + "version": "0.9.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.65.tgz", + "integrity": "sha512-sH9mu2GEIVuc6cs6HxsmCXn6KKzCa5D+Zyl1Pt9d2S4FKqSB17Fc4mVukCOMW7wUR9UChKTbxmByGJK+4xwdCA==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-webgl": { - "version": "0.19.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.64.tgz", - "integrity": "sha512-cxTkMPAXPQAZnWqahNu7ff9mbJvM1sQqKnZWiFZAHTsZXym4oa3KCB4pjH4didSyYkhkPY/17E8I0UOUpvv0Yw==", + "version": "0.19.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.65.tgz", + "integrity": "sha512-gPwP8ozqrLFWOlo9eh2I+acxq0Z6obG7GpL8HpJ+B+q6+vjfxoXHQ6vV04W90aoAvbLpScHcT/JtXA58GcH2vw==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/headless": { - "version": "5.6.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-5.6.0-beta.64.tgz", - "integrity": "sha512-my08kgH2K3CBEtBg/o8lamtD6BYNBv03Akq747Lajv0QzOiwan7B4r2xdbA6i9sovB+MdjFs0XP1ksc3EpKakg==" + "version": "5.6.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-5.6.0-beta.65.tgz", + "integrity": "sha512-gQICZsBkFHQEb/K+dc+KN4u5aBwrDPgai0S7W8/KT7fqTPWz8Cgjq119WQLshnzfLeMMFPYGttNHFGUbpp/wmw==" }, "node_modules/@xterm/xterm": { - "version": "5.6.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.64.tgz", - "integrity": "sha512-iSKS6tQTFpoN5y487eptlxkUT0jqK5hrvtFQMLugMcQdn7gCUCiFGa4Z1RdqKYSGvAypka+b9gMKPrKWZ7Q3yQ==" + "version": "5.6.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.65.tgz", + "integrity": "sha512-o6IIg4hqs994gtSQMbzQM6OUeLIXPG6RUxjoref0KJX4PIa/BqQjwQLPuSxnjOFeRQIvhZ2mSAPfGWJQ6jEGAg==" }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", @@ -13520,9 +13520,9 @@ } }, "node_modules/node-pty": { - "version": "1.1.0-beta21", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta21.tgz", - "integrity": "sha512-FYpnY9g8qMQLTpqyeY9NVli6YfCWwvG6v6gmaDBbPjlc1VMp/+Zivq0SStDrRr1aciGnFCZzpL0BzdMnmbDnAw==", + "version": "1.1.0-beta22", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta22.tgz", + "integrity": "sha512-CpT334H2oAIULlENvd9U+VBW4ZL+G3clOnpXYzUIurlPCLnl/9xen/KDHBLRcwhZuWcHxIrsCxR1TDCdVDtr0w==", "hasInstallScript": true, "dependencies": { "node-addon-api": "^7.1.0" @@ -18579,9 +18579,9 @@ "dev": true }, "node_modules/typescript": { - "version": "5.7.0-dev.20240903", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.0-dev.20240903.tgz", - "integrity": "sha512-XTUc5uVwBbLlT0v3FqTx9sDN1MLQnT5mwSC3JefCrcKT6Zv+rPcQE7HLKM9IsrNiM1tiaQvamJTgVH0S+UMH2A==", + "version": "5.7.0-dev.20240927", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.0-dev.20240927.tgz", + "integrity": "sha512-IWKZHTHAlS8BglLp8iM4rUHhy0h79B9r9vj6b6zpa8U38ofctFS1fLiKY7okZ3JYeG15kUHuOwsLwOmvc5+e1Q==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 1aea8bae9b260..5c441319f438f 100644 --- a/package.json +++ b/package.json @@ -11,17 +11,13 @@ "scripts": { "test": "echo Please run any of the test scripts from the scripts folder.", "test-browser": "npx playwright install && node test/unit/browser/index.js", - "test-browser-amd": "npx playwright install && node test/unit/browser/index.amd.js", "test-browser-no-install": "node test/unit/browser/index.js", - "test-browser-amd-no-install": "node test/unit/browser/index.amd.js", "test-node": "mocha test/unit/node/index.mjs --delay --ui=tdd --timeout=5000 --exit", - "test-node-amd": "mocha test/unit/node/index.amd.js --delay --ui=tdd --timeout=5000 --exit", "test-extension": "vscode-test", "preinstall": "node build/npm/preinstall.js", "postinstall": "node build/npm/postinstall.js", "compile": "node ./node_modules/gulp/bin/gulp.js compile", "watch": "npm-run-all -lp watch-client watch-extensions", - "watch-amd": "npm-run-all -lp watch-client-amd watch-extensions", "watchd": "deemon npm run watch", "watch-webd": "deemon npm run watch-web", "kill-watchd": "deemon --kill npm run watch", @@ -29,7 +25,6 @@ "restart-watchd": "deemon --restart npm run watch", "restart-watch-webd": "deemon --restart npm run watch-web", "watch-client": "node --max-old-space-size=8192 ./node_modules/gulp/bin/gulp.js watch-client", - "watch-client-amd": "node --max-old-space-size=8192 ./node_modules/gulp/bin/gulp.js watch-client-amd", "watch-clientd": "deemon npm run watch-client", "kill-watch-clientd": "deemon --kill npm run watch-client", "watch-extensions": "node --max-old-space-size=8192 ./node_modules/gulp/bin/gulp.js watch-extensions watch-extension-media", @@ -88,14 +83,14 @@ "@vscode/windows-mutex": "^0.5.0", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "^0.2.0-beta.47", - "@xterm/addon-image": "^0.9.0-beta.64", - "@xterm/addon-search": "^0.16.0-beta.64", - "@xterm/addon-serialize": "^0.14.0-beta.64", - "@xterm/addon-unicode11": "^0.9.0-beta.64", - "@xterm/addon-webgl": "^0.19.0-beta.64", - "@xterm/headless": "^5.6.0-beta.64", - "@xterm/xterm": "^5.6.0-beta.64", + "@xterm/addon-clipboard": "^0.2.0-beta.48", + "@xterm/addon-image": "^0.9.0-beta.65", + "@xterm/addon-search": "^0.16.0-beta.65", + "@xterm/addon-serialize": "^0.14.0-beta.65", + "@xterm/addon-unicode11": "^0.9.0-beta.65", + "@xterm/addon-webgl": "^0.19.0-beta.65", + "@xterm/headless": "^5.6.0-beta.65", + "@xterm/xterm": "^5.6.0-beta.65", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.3", @@ -104,7 +99,7 @@ "native-is-elevated": "0.7.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta21", + "node-pty": "^1.1.0-beta22", "open": "^8.4.2", "tas-client-umd": "0.2.0", "v8-inspect-profiler": "^0.1.1", @@ -216,7 +211,7 @@ "ts-node": "^10.9.1", "tsec": "0.2.7", "tslib": "^2.6.3", - "typescript": "^5.7.0-dev.20240903", + "typescript": "^5.7.0-dev.20240927", "util": "^0.12.4", "webpack": "^5.94.0", "webpack-cli": "^5.1.4", diff --git a/remote/package-lock.json b/remote/package-lock.json index 58725751af9ee..5f8891ee061a1 100644 --- a/remote/package-lock.json +++ b/remote/package-lock.json @@ -20,14 +20,14 @@ "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "^0.2.0-beta.47", - "@xterm/addon-image": "^0.9.0-beta.64", - "@xterm/addon-search": "^0.16.0-beta.64", - "@xterm/addon-serialize": "^0.14.0-beta.64", - "@xterm/addon-unicode11": "^0.9.0-beta.64", - "@xterm/addon-webgl": "^0.19.0-beta.64", - "@xterm/headless": "^5.6.0-beta.64", - "@xterm/xterm": "^5.6.0-beta.64", + "@xterm/addon-clipboard": "^0.2.0-beta.48", + "@xterm/addon-image": "^0.9.0-beta.65", + "@xterm/addon-search": "^0.16.0-beta.65", + "@xterm/addon-serialize": "^0.14.0-beta.65", + "@xterm/addon-unicode11": "^0.9.0-beta.65", + "@xterm/addon-webgl": "^0.19.0-beta.65", + "@xterm/headless": "^5.6.0-beta.65", + "@xterm/xterm": "^5.6.0-beta.65", "cookie": "^0.4.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", @@ -35,7 +35,7 @@ "kerberos": "2.1.1", "minimist": "^1.2.6", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta21", + "node-pty": "^1.1.0-beta22", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", @@ -233,65 +233,65 @@ "hasInstallScript": true }, "node_modules/@xterm/addon-clipboard": { - "version": "0.2.0-beta.47", - "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.47.tgz", - "integrity": "sha512-mJHV1770gwVckj4mgjdxegt4zLL5WGCoJblTqaLbgEF7xOwsJUzvGk38qsZ4ZpdTa2ti76H0pkb1CpZGrXL9qg==", + "version": "0.2.0-beta.48", + "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.48.tgz", + "integrity": "sha512-oTrGoGMOQaW7PINAShhNR3duV8l2No/DbJ9rtfSBjfoQ9clWe0K+4fUHdJIuzW65AZsiLo9oh5IbHLWxlFP3Jg==", "dependencies": { "js-base64": "^3.7.5" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-image": { - "version": "0.9.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.64.tgz", - "integrity": "sha512-1Aqqytx/z/Khecf5xrO++f/p5EQX4uG87TbbAmE0OQys/JgKMnNggDzqon5bpHboimLfQiFPw716NbTqMphjfw==", + "version": "0.9.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.65.tgz", + "integrity": "sha512-Ud5FI5cGtpbz8yYCHC4QINlbC1K04Mex1JD5oAWPFwjlOz/Si/DhqbY1QBDl6QrUmSUUTZc5DKT3v3nN5WbZxQ==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-search": { - "version": "0.16.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.64.tgz", - "integrity": "sha512-vUsvTkEOFJwv8nVtiiGr/vTMeQhu62VkUejY2h1+yZagnVEusGVPU1JYoqBTLu5HM4cFiTGsJYXFI/0apASXYA==", + "version": "0.16.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.65.tgz", + "integrity": "sha512-eHfbbgFCS3AcD8YSvGFIkW9NW4pfGHrtRDWIojM/zqmyi3JaCmHUgZmlxbaANwBlgLiNpJLDq7cmoz//86NgGw==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-serialize": { - "version": "0.14.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.64.tgz", - "integrity": "sha512-0AqVveTV3Pr9Lp+beJYOP5WuRvIrPSDGAK24da7BRGcLIKVq8pok1FdlM9jPeUbkX0DKo6Ortm77qeb2Z+n8+A==", + "version": "0.14.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.65.tgz", + "integrity": "sha512-NlvXVtFAHpLKEDzd+6/68yPFQ4Oe02jvQH6+a8p+gcxbSEyYj1l0sqqeABQ3gC5QDCmQepk6BQVB8Rpz/e4HgQ==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-unicode11": { - "version": "0.9.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.64.tgz", - "integrity": "sha512-3+PKu+DXFq32xlsYfnI058/T8dTY2tQhRpJLP2CNR/jVWk5uBkVO0dBV0Srqj5QOAlAhzzZuS6TbsVRXORptqw==", + "version": "0.9.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.65.tgz", + "integrity": "sha512-sH9mu2GEIVuc6cs6HxsmCXn6KKzCa5D+Zyl1Pt9d2S4FKqSB17Fc4mVukCOMW7wUR9UChKTbxmByGJK+4xwdCA==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-webgl": { - "version": "0.19.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.64.tgz", - "integrity": "sha512-cxTkMPAXPQAZnWqahNu7ff9mbJvM1sQqKnZWiFZAHTsZXym4oa3KCB4pjH4didSyYkhkPY/17E8I0UOUpvv0Yw==", + "version": "0.19.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.65.tgz", + "integrity": "sha512-gPwP8ozqrLFWOlo9eh2I+acxq0Z6obG7GpL8HpJ+B+q6+vjfxoXHQ6vV04W90aoAvbLpScHcT/JtXA58GcH2vw==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/headless": { - "version": "5.6.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-5.6.0-beta.64.tgz", - "integrity": "sha512-my08kgH2K3CBEtBg/o8lamtD6BYNBv03Akq747Lajv0QzOiwan7B4r2xdbA6i9sovB+MdjFs0XP1ksc3EpKakg==" + "version": "5.6.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-5.6.0-beta.65.tgz", + "integrity": "sha512-gQICZsBkFHQEb/K+dc+KN4u5aBwrDPgai0S7W8/KT7fqTPWz8Cgjq119WQLshnzfLeMMFPYGttNHFGUbpp/wmw==" }, "node_modules/@xterm/xterm": { - "version": "5.6.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.64.tgz", - "integrity": "sha512-iSKS6tQTFpoN5y487eptlxkUT0jqK5hrvtFQMLugMcQdn7gCUCiFGa4Z1RdqKYSGvAypka+b9gMKPrKWZ7Q3yQ==" + "version": "5.6.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.65.tgz", + "integrity": "sha512-o6IIg4hqs994gtSQMbzQM6OUeLIXPG6RUxjoref0KJX4PIa/BqQjwQLPuSxnjOFeRQIvhZ2mSAPfGWJQ6jEGAg==" }, "node_modules/agent-base": { "version": "7.1.1", @@ -748,9 +748,9 @@ } }, "node_modules/node-pty": { - "version": "1.1.0-beta21", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta21.tgz", - "integrity": "sha512-FYpnY9g8qMQLTpqyeY9NVli6YfCWwvG6v6gmaDBbPjlc1VMp/+Zivq0SStDrRr1aciGnFCZzpL0BzdMnmbDnAw==", + "version": "1.1.0-beta22", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta22.tgz", + "integrity": "sha512-CpT334H2oAIULlENvd9U+VBW4ZL+G3clOnpXYzUIurlPCLnl/9xen/KDHBLRcwhZuWcHxIrsCxR1TDCdVDtr0w==", "hasInstallScript": true, "dependencies": { "node-addon-api": "^7.1.0" diff --git a/remote/package.json b/remote/package.json index c107b048e45c0..0d0a37e4b9046 100644 --- a/remote/package.json +++ b/remote/package.json @@ -15,14 +15,14 @@ "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "^0.2.0-beta.47", - "@xterm/addon-image": "^0.9.0-beta.64", - "@xterm/addon-search": "^0.16.0-beta.64", - "@xterm/addon-serialize": "^0.14.0-beta.64", - "@xterm/addon-unicode11": "^0.9.0-beta.64", - "@xterm/addon-webgl": "^0.19.0-beta.64", - "@xterm/headless": "^5.6.0-beta.64", - "@xterm/xterm": "^5.6.0-beta.64", + "@xterm/addon-clipboard": "^0.2.0-beta.48", + "@xterm/addon-image": "^0.9.0-beta.65", + "@xterm/addon-search": "^0.16.0-beta.65", + "@xterm/addon-serialize": "^0.14.0-beta.65", + "@xterm/addon-unicode11": "^0.9.0-beta.65", + "@xterm/addon-webgl": "^0.19.0-beta.65", + "@xterm/headless": "^5.6.0-beta.65", + "@xterm/xterm": "^5.6.0-beta.65", "cookie": "^0.4.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", @@ -30,7 +30,7 @@ "kerberos": "2.1.1", "minimist": "^1.2.6", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta21", + "node-pty": "^1.1.0-beta22", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", diff --git a/remote/web/package-lock.json b/remote/web/package-lock.json index b971ca265f03e..04199f4e652db 100644 --- a/remote/web/package-lock.json +++ b/remote/web/package-lock.json @@ -13,13 +13,13 @@ "@vscode/iconv-lite-umd": "0.7.0", "@vscode/tree-sitter-wasm": "^0.0.4", "@vscode/vscode-languagedetection": "1.0.21", - "@xterm/addon-clipboard": "^0.2.0-beta.47", - "@xterm/addon-image": "^0.9.0-beta.64", - "@xterm/addon-search": "^0.16.0-beta.64", - "@xterm/addon-serialize": "^0.14.0-beta.64", - "@xterm/addon-unicode11": "^0.9.0-beta.64", - "@xterm/addon-webgl": "^0.19.0-beta.64", - "@xterm/xterm": "^5.6.0-beta.64", + "@xterm/addon-clipboard": "^0.2.0-beta.48", + "@xterm/addon-image": "^0.9.0-beta.65", + "@xterm/addon-search": "^0.16.0-beta.65", + "@xterm/addon-serialize": "^0.14.0-beta.65", + "@xterm/addon-unicode11": "^0.9.0-beta.65", + "@xterm/addon-webgl": "^0.19.0-beta.65", + "@xterm/xterm": "^5.6.0-beta.65", "jschardet": "3.1.3", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", @@ -87,60 +87,60 @@ } }, "node_modules/@xterm/addon-clipboard": { - "version": "0.2.0-beta.47", - "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.47.tgz", - "integrity": "sha512-mJHV1770gwVckj4mgjdxegt4zLL5WGCoJblTqaLbgEF7xOwsJUzvGk38qsZ4ZpdTa2ti76H0pkb1CpZGrXL9qg==", + "version": "0.2.0-beta.48", + "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.48.tgz", + "integrity": "sha512-oTrGoGMOQaW7PINAShhNR3duV8l2No/DbJ9rtfSBjfoQ9clWe0K+4fUHdJIuzW65AZsiLo9oh5IbHLWxlFP3Jg==", "dependencies": { "js-base64": "^3.7.5" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-image": { - "version": "0.9.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.64.tgz", - "integrity": "sha512-1Aqqytx/z/Khecf5xrO++f/p5EQX4uG87TbbAmE0OQys/JgKMnNggDzqon5bpHboimLfQiFPw716NbTqMphjfw==", + "version": "0.9.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.65.tgz", + "integrity": "sha512-Ud5FI5cGtpbz8yYCHC4QINlbC1K04Mex1JD5oAWPFwjlOz/Si/DhqbY1QBDl6QrUmSUUTZc5DKT3v3nN5WbZxQ==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-search": { - "version": "0.16.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.64.tgz", - "integrity": "sha512-vUsvTkEOFJwv8nVtiiGr/vTMeQhu62VkUejY2h1+yZagnVEusGVPU1JYoqBTLu5HM4cFiTGsJYXFI/0apASXYA==", + "version": "0.16.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.65.tgz", + "integrity": "sha512-eHfbbgFCS3AcD8YSvGFIkW9NW4pfGHrtRDWIojM/zqmyi3JaCmHUgZmlxbaANwBlgLiNpJLDq7cmoz//86NgGw==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-serialize": { - "version": "0.14.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.64.tgz", - "integrity": "sha512-0AqVveTV3Pr9Lp+beJYOP5WuRvIrPSDGAK24da7BRGcLIKVq8pok1FdlM9jPeUbkX0DKo6Ortm77qeb2Z+n8+A==", + "version": "0.14.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.65.tgz", + "integrity": "sha512-NlvXVtFAHpLKEDzd+6/68yPFQ4Oe02jvQH6+a8p+gcxbSEyYj1l0sqqeABQ3gC5QDCmQepk6BQVB8Rpz/e4HgQ==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-unicode11": { - "version": "0.9.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.64.tgz", - "integrity": "sha512-3+PKu+DXFq32xlsYfnI058/T8dTY2tQhRpJLP2CNR/jVWk5uBkVO0dBV0Srqj5QOAlAhzzZuS6TbsVRXORptqw==", + "version": "0.9.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.65.tgz", + "integrity": "sha512-sH9mu2GEIVuc6cs6HxsmCXn6KKzCa5D+Zyl1Pt9d2S4FKqSB17Fc4mVukCOMW7wUR9UChKTbxmByGJK+4xwdCA==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/addon-webgl": { - "version": "0.19.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.64.tgz", - "integrity": "sha512-cxTkMPAXPQAZnWqahNu7ff9mbJvM1sQqKnZWiFZAHTsZXym4oa3KCB4pjH4didSyYkhkPY/17E8I0UOUpvv0Yw==", + "version": "0.19.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.65.tgz", + "integrity": "sha512-gPwP8ozqrLFWOlo9eh2I+acxq0Z6obG7GpL8HpJ+B+q6+vjfxoXHQ6vV04W90aoAvbLpScHcT/JtXA58GcH2vw==", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.64" + "@xterm/xterm": "^5.6.0-beta.65" } }, "node_modules/@xterm/xterm": { - "version": "5.6.0-beta.64", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.64.tgz", - "integrity": "sha512-iSKS6tQTFpoN5y487eptlxkUT0jqK5hrvtFQMLugMcQdn7gCUCiFGa4Z1RdqKYSGvAypka+b9gMKPrKWZ7Q3yQ==" + "version": "5.6.0-beta.65", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.65.tgz", + "integrity": "sha512-o6IIg4hqs994gtSQMbzQM6OUeLIXPG6RUxjoref0KJX4PIa/BqQjwQLPuSxnjOFeRQIvhZ2mSAPfGWJQ6jEGAg==" }, "node_modules/js-base64": { "version": "3.7.7", diff --git a/remote/web/package.json b/remote/web/package.json index 27be6a503bdc7..a4a18b9369cb0 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -8,13 +8,13 @@ "@vscode/iconv-lite-umd": "0.7.0", "@vscode/tree-sitter-wasm": "^0.0.4", "@vscode/vscode-languagedetection": "1.0.21", - "@xterm/addon-clipboard": "^0.2.0-beta.47", - "@xterm/addon-image": "^0.9.0-beta.64", - "@xterm/addon-search": "^0.16.0-beta.64", - "@xterm/addon-serialize": "^0.14.0-beta.64", - "@xterm/addon-unicode11": "^0.9.0-beta.64", - "@xterm/addon-webgl": "^0.19.0-beta.64", - "@xterm/xterm": "^5.6.0-beta.64", + "@xterm/addon-clipboard": "^0.2.0-beta.48", + "@xterm/addon-image": "^0.9.0-beta.65", + "@xterm/addon-search": "^0.16.0-beta.65", + "@xterm/addon-serialize": "^0.14.0-beta.65", + "@xterm/addon-unicode11": "^0.9.0-beta.65", + "@xterm/addon-webgl": "^0.19.0-beta.65", + "@xterm/xterm": "^5.6.0-beta.65", "jschardet": "3.1.3", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", diff --git a/scripts/code-web.js b/scripts/code-web.js index f2dc1ff046bdb..f05c934cadfaa 100644 --- a/scripts/code-web.js +++ b/scripts/code-web.js @@ -74,10 +74,7 @@ async function main() { openSystemBrowser = true; } - if (!fs.existsSync(path.join(APP_ROOT, 'src2')) && !fs.existsSync(path.join(APP_ROOT, 'out-build', 'amd'))) { - serverArgs.push('--esm'); - } - + serverArgs.push('--esm'); // TODO@esm this should be the default serverArgs.push('--sourcesPath', APP_ROOT); serverArgs.push(...process.argv.slice(2).filter(v => !v.startsWith('--playground') && v !== '--no-playground')); diff --git a/scripts/test-amd.bat b/scripts/test-amd.bat deleted file mode 100644 index 4ecd8a43400be..0000000000000 --- a/scripts/test-amd.bat +++ /dev/null @@ -1,31 +0,0 @@ -@echo off -setlocal - -set ELECTRON_RUN_AS_NODE= - -pushd %~dp0\.. - -:: Get Code.exe location -for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a -set NAMESHORT=%NAMESHORT: "=% -set NAMESHORT=%NAMESHORT:"=%.exe -set CODE=".build\electron\%NAMESHORT%" - -:: Download Electron if needed -call node build\lib\electron.js -if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron - -:: Run tests -set ELECTRON_ENABLE_LOGGING=1 -%CODE% .\test\unit\electron\index.amd.js --crash-reporter-directory=%~dp0\..\.build\crashes %* - -popd - -endlocal - -:: app.exit(0) is exiting with code 255 in Electron 1.7.4. -:: See https://github.com/microsoft/vscode/issues/28582 -echo errorlevel: %errorlevel% -if %errorlevel% == 255 set errorlevel=0 - -exit /b %errorlevel% diff --git a/scripts/test-amd.sh b/scripts/test-amd.sh deleted file mode 100755 index be45e09034846..0000000000000 --- a/scripts/test-amd.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -set -e - -if [[ "$OSTYPE" == "darwin"* ]]; then - realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } - ROOT=$(dirname $(dirname $(realpath "$0"))) -else - ROOT=$(dirname $(dirname $(readlink -f $0))) - # --disable-dev-shm-usage: when run on docker containers where size of /dev/shm - # partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory - LINUX_EXTRA_ARGS="--disable-dev-shm-usage" -fi - -cd $ROOT - -if [[ "$OSTYPE" == "darwin"* ]]; then - NAME=`node -p "require('./product.json').nameLong"` - CODE="./.build/electron/$NAME.app/Contents/MacOS/Electron" -else - NAME=`node -p "require('./product.json').applicationName"` - CODE=".build/electron/$NAME" -fi - -VSCODECRASHDIR=$ROOT/.build/crashes - -# Node modules -test -d node_modules || npm i - -# Get electron -npm run electron - -# Unit Tests -if [[ "$OSTYPE" == "darwin"* ]]; then - cd $ROOT ; ulimit -n 4096 ; \ - ELECTRON_ENABLE_LOGGING=1 \ - "$CODE" \ - test/unit/electron/index.amd.js --crash-reporter-directory=$VSCODECRASHDIR "$@" -else - cd $ROOT ; \ - ELECTRON_ENABLE_LOGGING=1 \ - "$CODE" \ - test/unit/electron/index.amd.js --crash-reporter-directory=$VSCODECRASHDIR $LINUX_EXTRA_ARGS "$@" -fi diff --git a/scripts/test-integration-amd.bat b/scripts/test-integration-amd.bat deleted file mode 100644 index 96231152b91a9..0000000000000 --- a/scripts/test-integration-amd.bat +++ /dev/null @@ -1,119 +0,0 @@ -@echo off -setlocal - -pushd %~dp0\.. - -set VSCODEUSERDATADIR=%TEMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,2% -set VSCODECRASHDIR=%~dp0\..\.build\crashes -set VSCODELOGSDIR=%~dp0\..\.build\logs\integration-tests - -:: Figure out which Electron to use for running tests -if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( - chcp 65001 - set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat - set VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE=1 - - echo Running integration tests out of sources. -) else ( - set VSCODE_CLI=1 - set ELECTRON_ENABLE_LOGGING=1 - - echo Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build. -) - -echo Storing crash reports into '%VSCODECRASHDIR%'. -echo Storing log files into '%VSCODELOGSDIR%'. - - -:: Tests standalone (AMD) - -echo. -echo ### node.js integration tests -call .\scripts\test-amd.bat --runGlob **\*.integrationTest.js %* -if %errorlevel% neq 0 exit /b %errorlevel% - - -:: Tests in the extension host - -set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR% - -echo. -echo ### API tests (folder) -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests %API_TESTS_EXTRA_ARGS% -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### API tests (workspace) -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests %API_TESTS_EXTRA_ARGS% -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### Colorize tests -call npm run test-extension -l vscode-colorize-tests -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### TypeScript tests -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\typescript-language-features --extensionTestsPath=%~dp0\..\extensions\typescript-language-features\out\test\unit %API_TESTS_EXTRA_ARGS% -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### Markdown tests -call npm run test-extension -l markdown-language-features -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### Emmet tests -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\emmet\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test %API_TESTS_EXTRA_ARGS% -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### Git tests -for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i -set GITWORKSPACE=%TEMPDIR%\git-%RANDOM% -mkdir %GITWORKSPACE% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test %API_TESTS_EXTRA_ARGS% -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### Ipynb tests -call npm run test-extension -l ipynb -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### Notebook Output tests -call npm run test-extension -l notebook-renderers -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### Configuration editing tests -set CFWORKSPACE=%TEMPDIR%\cf-%RANDOM% -mkdir %CFWORKSPACE% -call npm run test-extension -l configuration-editing -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### GitHub Authentication tests -call npm run test-extension -l github-authentication -if %errorlevel% neq 0 exit /b %errorlevel% - -:: Tests standalone (CommonJS) - -echo. -echo ### CSS tests -call %~dp0\node-electron.bat %~dp0\..\extensions\css-language-features/server/test/index.js -if %errorlevel% neq 0 exit /b %errorlevel% - -echo. -echo ### HTML tests -call %~dp0\node-electron.bat %~dp0\..\extensions\html-language-features/server/test/index.js -if %errorlevel% neq 0 exit /b %errorlevel% - - -:: Cleanup - -rmdir /s /q %VSCODEUSERDATADIR% - -popd - -endlocal diff --git a/scripts/test-integration-amd.sh b/scripts/test-integration-amd.sh deleted file mode 100755 index 70f50cc306ea8..0000000000000 --- a/scripts/test-integration-amd.sh +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env bash -set -e - -if [[ "$OSTYPE" == "darwin"* ]]; then - realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } - ROOT=$(dirname $(dirname $(realpath "$0"))) -else - ROOT=$(dirname $(dirname $(readlink -f $0))) - # --disable-dev-shm-usage: when run on docker containers where size of /dev/shm - # partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory - LINUX_EXTRA_ARGS="--disable-dev-shm-usage" -fi - -VSCODEUSERDATADIR=`mktemp -d 2>/dev/null` -VSCODECRASHDIR=$ROOT/.build/crashes -VSCODELOGSDIR=$ROOT/.build/logs/integration-tests - -cd $ROOT - -# Figure out which Electron to use for running tests -if [ -z "$INTEGRATION_TEST_ELECTRON_PATH" ] -then - INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh" - - echo "Running integration tests out of sources." -else - export VSCODE_CLI=1 - export ELECTRON_ENABLE_LOGGING=1 - - echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build." -fi - -echo "Storing crash reports into '$VSCODECRASHDIR'." -echo "Storing log files into '$VSCODELOGSDIR'." - - -# Tests standalone (AMD) - -echo -echo "### node.js integration tests" -echo -./scripts/test-amd.sh --runGlob **/*.integrationTest.js "$@" - - -# Tests in the extension host - -API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR" - -if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then - kill_app() { true; } -else - kill_app() { killall $INTEGRATION_TEST_APP_NAME || true; } -fi - -echo -echo "### API tests (folder)" -echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests $API_TESTS_EXTRA_ARGS -kill_app - -echo -echo "### API tests (workspace)" -echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests $API_TESTS_EXTRA_ARGS -kill_app - -echo -echo "### Colorize tests" -echo -npm run test-extension -l vscode-colorize-tests -kill_app - -echo -echo "### TypeScript tests" -echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test/unit $API_TESTS_EXTRA_ARGS -kill_app - -echo -echo "### Markdown tests" -echo -npm run test-extension -l markdown-language-features -kill_app - -echo -echo "### Emmet tests" -echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/emmet/test-workspace --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test $API_TESTS_EXTRA_ARGS -kill_app - -echo -echo "### Git tests" -echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test $API_TESTS_EXTRA_ARGS -kill_app - -echo -echo "### Ipynb tests" -echo -npm run test-extension -l ipynb -kill_app - -echo -echo "### Notebook Output tests" -echo -npm run test-extension -l notebook-renderers -kill_app - -echo -echo "### Configuration editing tests" -echo -npm run test-extension -l configuration-editing -kill_app - -echo -echo "### GitHub Authentication tests" -echo -npm run test-extension -l github-authentication -kill_app - -# Tests standalone (CommonJS) - -echo -echo "### CSS tests" -echo -cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js - -echo -echo "### HTML tests" -echo -cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js - - -# Cleanup - -rm -rf $VSCODEUSERDATADIR diff --git a/src/bootstrap-cli.js b/src/bootstrap-cli.ts similarity index 95% rename from src/bootstrap-cli.js rename to src/bootstrap-cli.ts index 8f077a0eeaf2a..f454b830ea64c 100644 --- a/src/bootstrap-cli.js +++ b/src/bootstrap-cli.ts @@ -3,9 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check -'use strict'; - // Delete `VSCODE_CWD` very early. We have seen // reports where `code .` would use the wrong // current working directory due to our variable diff --git a/src/bootstrap-amd.js b/src/bootstrap-esm.ts similarity index 53% rename from src/bootstrap-amd.js rename to src/bootstrap-esm.ts index 9c8daf5575686..b0c6d142a4f42 100644 --- a/src/bootstrap-amd.js +++ b/src/bootstrap-esm.ts @@ -3,15 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check -'use strict'; +/* eslint-disable local/code-import-patterns */ -/** - * @import { INLSConfiguration } from './vs/nls' - * @import { IProductConfiguration } from './vs/base/common/product' - */ - -// ESM-uncomment-begin import * as path from 'path'; import * as fs from 'fs'; import { fileURLToPath } from 'url'; @@ -19,11 +12,9 @@ import { createRequire, register } from 'node:module'; import { product, pkg } from './bootstrap-meta.js'; import './bootstrap-node.js'; import * as performance from './vs/base/common/performance.js'; +import { INLSConfiguration } from './vs/nls.js'; -/** @ts-ignore */ const require = createRequire(import.meta.url); -/** @type any */ -const module = { exports: {} }; const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Install a hook to module resolution to map 'fs' to 'original-fs' @@ -44,49 +35,23 @@ if (process.env['ELECTRON_RUN_AS_NODE'] || process.versions['electron']) { }`; register(`data:text/javascript;base64,${Buffer.from(jsCode).toString('base64')}`, import.meta.url); } -// ESM-uncomment-end - -// VSCODE_GLOBALS: package/product.json -/** @type Partial */ -// ESM-comment-begin -// globalThis._VSCODE_PRODUCT_JSON = require('./bootstrap-meta').product; -// ESM-comment-end -// ESM-uncomment-begin + +// Prepare globals that are needed for running globalThis._VSCODE_PRODUCT_JSON = { ...product }; -// ESM-uncomment-end if (process.env['VSCODE_DEV']) { - // Patch product overrides when running out of sources try { - // @ts-ignore const overrides = require('../product.overrides.json'); globalThis._VSCODE_PRODUCT_JSON = Object.assign(globalThis._VSCODE_PRODUCT_JSON, overrides); } catch (error) { /* ignore */ } } -// ESM-comment-begin -// globalThis._VSCODE_PACKAGE_JSON = require('./bootstrap-meta').pkg; -// ESM-comment-end -// ESM-uncomment-begin globalThis._VSCODE_PACKAGE_JSON = { ...pkg }; -// ESM-uncomment-end - -// VSCODE_GLOBALS: file root of all resources globalThis._VSCODE_FILE_ROOT = __dirname; -// ESM-comment-begin -// const bootstrapNode = require('./bootstrap-node'); -// const performance = require(`./vs/base/common/performance`); -// const fs = require('fs'); -// ESM-comment-end - //#region NLS helpers -/** @type {Promise | undefined} */ -let setupNLSResult = undefined; +let setupNLSResult: Promise | undefined = undefined; -/** - * @returns {Promise} - */ -function setupNLS() { +function setupNLS(): Promise { if (!setupNLSResult) { setupNLSResult = doSetupNLS(); } @@ -94,20 +59,14 @@ function setupNLS() { return setupNLSResult; } -/** - * @returns {Promise} - */ -async function doSetupNLS() { - performance.mark('code/amd/willLoadNls'); +async function doSetupNLS(): Promise { + performance.mark('code/willLoadNls'); - /** @type {INLSConfiguration | undefined} */ - let nlsConfig = undefined; + let nlsConfig: INLSConfiguration | undefined = undefined; - /** @type {string | undefined} */ - let messagesFile; + let messagesFile: string | undefined; if (process.env['VSCODE_NLS_CONFIG']) { try { - /** @type {INLSConfiguration} */ nlsConfig = JSON.parse(process.env['VSCODE_NLS_CONFIG']); if (nlsConfig?.languagePack?.messagesFile) { messagesFile = nlsConfig.languagePack.messagesFile; @@ -152,89 +111,28 @@ async function doSetupNLS() { } } - performance.mark('code/amd/didLoadNls'); + performance.mark('code/didLoadNls'); return nlsConfig; } //#endregion -//#region Loader Config +//#region ESM Loading -// ESM-uncomment-begin -/** - * @param {string=} entrypoint - * @param {(value: any) => void} [onLoad] - * @param {(err: Error) => void} [onError] - */ -module.exports.load = function (entrypoint, onLoad, onError) { - if (!entrypoint) { +export function load(esModule: string | undefined, onLoad?: (value: any) => void, onError?: (err: Error) => void): void { + if (!esModule) { return; } - entrypoint = `./${entrypoint}.js`; - onLoad = onLoad || function () { }; onError = onError || function (err) { console.error(err); }; setupNLS().then(() => { performance.mark(`code/fork/willLoadCode`); - import(entrypoint).then(onLoad, onError); + import([`./${esModule}.js`].join('/') /* workaround to prevent esbuild from inlining this */).then(onLoad, onError); }); -}; -// ESM-uncomment-end - -// ESM-comment-begin -// // @ts-ignore -// const loader = require('./vs/loader'); -// -// loader.config({ -// baseUrl: bootstrapNode.fileUriFromPath(__dirname, { isWindows: process.platform === 'win32' }), -// catchError: true, -// nodeRequire, -// amdModulesPattern: /^vs\//, -// recordStats: true -// }); -// -// // Running in Electron -// if (process.env['ELECTRON_RUN_AS_NODE'] || process.versions['electron']) { -// loader.define('fs', ['original-fs'], function (/** @type {import('fs')} */originalFS) { -// return originalFS; // replace the patched electron fs with the original node fs for all AMD code -// }); -// } -// -// /** -// * @param {string=} entrypoint -// * @param {(value: any) => void} [onLoad] -// * @param {(err: Error) => void} [onError] -// */ -// module.exports.load = function (entrypoint, onLoad, onError) { -// if (!entrypoint) { -// return; -// } -// -// // code cache config -// if (process.env['VSCODE_CODE_CACHE_PATH']) { -// loader.config({ -// nodeCachedData: { -// path: process.env['VSCODE_CODE_CACHE_PATH'], -// seed: entrypoint -// } -// }); -// } -// -// onLoad = onLoad || function () { }; -// onError = onError || function (err) { console.error(err); }; -// -// setupNLS().then(() => { -// performance.mark('code/fork/willLoadCode'); -// loader([entrypoint], onLoad, onError); -// }); -// }; -// ESM-comment-end +} //#endregion -// ESM-uncomment-begin -export const load = module.exports.load; -// ESM-uncomment-end diff --git a/src/bootstrap-fork.js b/src/bootstrap-fork.ts similarity index 74% rename from src/bootstrap-fork.js rename to src/bootstrap-fork.ts index 129517b608eec..3303d442ee712 100644 --- a/src/bootstrap-fork.js +++ b/src/bootstrap-fork.ts @@ -3,19 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check -'use strict'; - -// ESM-comment-begin -// const performance = require('./vs/base/common/performance'); -// const bootstrapNode = require('./bootstrap-node'); -// const bootstrapAmd = require('./bootstrap-amd'); -// ESM-comment-end -// ESM-uncomment-begin +/* eslint-disable local/code-import-patterns */ + import * as performance from './vs/base/common/performance.js'; -import * as bootstrapNode from './bootstrap-node.js'; -import * as bootstrapAmd from './bootstrap-amd.js'; -// ESM-uncomment-end +import { removeGlobalNodeJsModuleLookupPaths, devInjectNodeModuleLookupPath } from './bootstrap-node.js'; +import { load } from './bootstrap-esm.js'; performance.mark('code/fork/start'); @@ -23,13 +15,10 @@ performance.mark('code/fork/start'); configureCrashReporter(); // Remove global paths from the node module lookup (node.js only) -bootstrapNode.removeGlobalNodeJsModuleLookupPaths(); - -// Enable ASAR in our forked processes -bootstrapNode.enableASARSupport(); +removeGlobalNodeJsModuleLookupPaths(); if (process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']) { - bootstrapNode.devInjectNodeModuleLookupPath(process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']); + devInjectNodeModuleLookupPath(process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']); } // Configure: pipe logging to parent process @@ -47,27 +36,22 @@ if (process.env['VSCODE_PARENT_PID']) { terminateWhenParentTerminates(); } -// Load AMD entry point -bootstrapAmd.load(process.env['VSCODE_AMD_ENTRYPOINT']); +// Load ESM entry point +load(process.env['VSCODE_ESM_ENTRYPOINT']); //#region Helpers -function pipeLoggingToParent() { +function pipeLoggingToParent(): void { const MAX_STREAM_BUFFER_LENGTH = 1024 * 1024; const MAX_LENGTH = 100000; /** * Prevent circular stringify and convert arguments to real array - * - * @param {ArrayLike} args */ - function safeToArray(args) { - /** - * @type {string[]} - */ - const seen = []; - const argsArray = []; + function safeToString(args: ArrayLike): string { + const seen: string[] = []; + const argsArray: unknown[] = []; // Massage some arguments with special treatment if (args.length) { @@ -121,10 +105,7 @@ function pipeLoggingToParent() { } } - /** - * @param {{ type: string; severity: string; arguments: string; }} arg - */ - function safeSend(arg) { + function safeSend(arg: { type: string; severity: string; arguments: string }): void { try { if (process.send) { process.send(arg); @@ -134,10 +115,7 @@ function pipeLoggingToParent() { } } - /** - * @param {unknown} obj - */ - function isObject(obj) { + function isObject(obj: unknown): boolean { return typeof obj === 'object' && obj !== null && !Array.isArray(obj) @@ -145,12 +123,7 @@ function pipeLoggingToParent() { && !(obj instanceof Date); } - /** - * - * @param {'log' | 'warn' | 'error'} severity - * @param {string} args - */ - function safeSendConsoleMessage(severity, args) { + function safeSendConsoleMessage(severity: 'log' | 'warn' | 'error', args: string): void { safeSend({ type: '__$console', severity, arguments: args }); } @@ -159,14 +132,11 @@ function pipeLoggingToParent() { * * The wrapped property is not defined with `writable: false` to avoid * throwing errors, but rather a no-op setting. See https://github.com/microsoft/vscode-extension-telemetry/issues/88 - * - * @param {'log' | 'info' | 'warn' | 'error'} method - * @param {'log' | 'warn' | 'error'} severity */ - function wrapConsoleMethod(method, severity) { + function wrapConsoleMethod(method: 'log' | 'info' | 'warn' | 'error', severity: 'log' | 'warn' | 'error'): void { Object.defineProperty(console, method, { set: () => { }, - get: () => function () { safeSendConsoleMessage(severity, safeToArray(arguments)); }, + get: () => function () { safeSendConsoleMessage(severity, safeToString(arguments)); }, }); } @@ -175,20 +145,16 @@ function pipeLoggingToParent() { * renderer or CLI. It both calls through to the original method as well * as to console.log with complete lines so that they're made available * to the debugger/CLI. - * - * @param {'stdout' | 'stderr'} streamName - * @param {'log' | 'warn' | 'error'} severity */ - function wrapStream(streamName, severity) { + function wrapStream(streamName: 'stdout' | 'stderr', severity: 'log' | 'warn' | 'error'): void { const stream = process[streamName]; const original = stream.write; - /** @type string */ let buf = ''; Object.defineProperty(stream, 'write', { set: () => { }, - get: () => (/** @type {string | Buffer | Uint8Array} */ chunk, /** @type {BufferEncoding | undefined} */ encoding, /** @type {((err?: Error | undefined) => void) | undefined} */ callback) => { + get: () => (chunk: string | Buffer | Uint8Array, encoding: BufferEncoding | undefined, callback: ((err?: Error | undefined) => void) | undefined) => { buf += chunk.toString(encoding); const eol = buf.length > MAX_STREAM_BUFFER_LENGTH ? buf.length : buf.lastIndexOf('\n'); if (eol !== -1) { @@ -218,7 +184,7 @@ function pipeLoggingToParent() { wrapStream('stdout', 'log'); } -function handleExceptions() { +function handleExceptions(): void { // Handle uncaught exceptions process.on('uncaughtException', function (err) { @@ -231,7 +197,7 @@ function handleExceptions() { }); } -function terminateWhenParentTerminates() { +function terminateWhenParentTerminates(): void { const parentPid = Number(process.env['VSCODE_PARENT_PID']); if (typeof parentPid === 'number' && !isNaN(parentPid)) { @@ -245,13 +211,13 @@ function terminateWhenParentTerminates() { } } -function configureCrashReporter() { +function configureCrashReporter(): void { const crashReporterProcessType = process.env['VSCODE_CRASH_REPORTER_PROCESS_TYPE']; if (crashReporterProcessType) { try { - // @ts-ignore + //@ts-ignore if (process['crashReporter'] && typeof process['crashReporter'].addExtraParameter === 'function' /* Electron only */) { - // @ts-ignore + //@ts-ignore process['crashReporter'].addExtraParameter('processType', crashReporterProcessType); } } catch (error) { diff --git a/src/bootstrap-import.js b/src/bootstrap-import.ts similarity index 83% rename from src/bootstrap-import.js rename to src/bootstrap-import.ts index 070b0b93b4b79..c280170efb9b8 100644 --- a/src/bootstrap-import.js +++ b/src/bootstrap-import.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check +/* eslint-disable local/code-import-patterns */ // ********************************************************************* // * * @@ -18,15 +18,9 @@ import { join } from 'node:path'; // SEE https://nodejs.org/docs/latest/api/module.html#initialize -/** - * @type {Object.} - */ -const _specifierToUrl = {}; +const _specifierToUrl: Record = {}; -/** - * @param {string} injectPath - */ -export async function initialize(injectPath) { +export async function initialize(injectPath: string): Promise { // populate mappings const injectPackageJSONPath = fileURLToPath(new URL('../package.json', pathToFileURL(injectPath))); @@ -55,16 +49,10 @@ export async function initialize(injectPath) { console.log(`[bootstrap-import] Initialized node_modules redirector for: ${injectPath}`); } -/** - * @param {string | number} specifier - * @param {any} context - * @param {(arg0: any, arg1: any) => any} nextResolve - */ -export async function resolve(specifier, context, nextResolve) { +export async function resolve(specifier: string | number, context: any, nextResolve: (arg0: any, arg1: any) => any) { const newSpecifier = _specifierToUrl[specifier]; if (newSpecifier !== undefined) { - // console.log('[HOOKS]', specifier, '--->', newSpecifier); return { format: 'commonjs', shortCircuit: true, diff --git a/src/bootstrap-meta.js b/src/bootstrap-meta.ts similarity index 53% rename from src/bootstrap-meta.js rename to src/bootstrap-meta.ts index f9a968c82f50e..c17716c8d3133 100644 --- a/src/bootstrap-meta.js +++ b/src/bootstrap-meta.ts @@ -3,39 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check -'use strict'; +/* eslint-disable local/code-import-patterns */ -/** - * @import { IProductConfiguration } from './vs/base/common/product' - */ - -// ESM-uncomment-begin import { createRequire } from 'node:module'; +import type { IProductConfiguration } from './vs/base/common/product.js'; const require = createRequire(import.meta.url); -/** @type any */ -const module = { exports: {} }; -// ESM-uncomment-end -/** @type Partial & { BUILD_INSERT_PRODUCT_CONFIGURATION?: string } */ -let productObj = { BUILD_INSERT_PRODUCT_CONFIGURATION: 'BUILD_INSERT_PRODUCT_CONFIGURATION' }; // DO NOT MODIFY, PATCHED DURING BUILD +let productObj: Partial & { BUILD_INSERT_PRODUCT_CONFIGURATION?: string } = { BUILD_INSERT_PRODUCT_CONFIGURATION: 'BUILD_INSERT_PRODUCT_CONFIGURATION' }; // DO NOT MODIFY, PATCHED DURING BUILD if (productObj['BUILD_INSERT_PRODUCT_CONFIGURATION']) { - // @ts-ignore productObj = require('../product.json'); // Running out of sources } -/** @type object & { BUILD_INSERT_PACKAGE_CONFIGURATION?: string } */ let pkgObj = { BUILD_INSERT_PACKAGE_CONFIGURATION: 'BUILD_INSERT_PACKAGE_CONFIGURATION' }; // DO NOT MODIFY, PATCHED DURING BUILD if (pkgObj['BUILD_INSERT_PACKAGE_CONFIGURATION']) { - // @ts-ignore pkgObj = require('../package.json'); // Running out of sources } -module.exports.product = productObj; -module.exports.pkg = pkgObj; - -// ESM-uncomment-begin -export const product = module.exports.product; -export const pkg = module.exports.pkg; -// ESM-uncomment-end +export const product = productObj; +export const pkg = pkgObj; diff --git a/src/bootstrap-node.js b/src/bootstrap-node.ts similarity index 51% rename from src/bootstrap-node.js rename to src/bootstrap-node.ts index d9e8e7e9945c9..0fc29f14d2cf2 100644 --- a/src/bootstrap-node.js +++ b/src/bootstrap-node.ts @@ -3,26 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check -'use strict'; +/* eslint-disable local/code-import-patterns */ -// ESM-comment-begin -// const path = require('path'); -// const fs = require('fs'); -// const Module = require('module'); -// ESM-comment-end -// ESM-uncomment-begin import * as path from 'path'; import * as fs from 'fs'; import { fileURLToPath } from 'url'; import { createRequire } from 'node:module'; +import type { IProductConfiguration } from './vs/base/common/product'; -/** @ts-ignore */ const require = createRequire(import.meta.url); -/** @type any */ -const module = { exports: {} }; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -// ESM-uncomment-end // increase number of stack frames(from 10, https://github.com/v8/v8/wiki/Stack-Trace-API) Error.stackTraceLimit = 100; @@ -45,7 +35,7 @@ if (!process.env['VSCODE_HANDLES_SIGPIPE']) { // Setup current working directory in all our node & electron processes // - Windows: call `process.chdir()` to always set application folder as cwd // - all OS: store the `process.cwd()` inside `VSCODE_CWD` for consistent lookups -function setupCurrentWorkingDirectory() { +function setupCurrentWorkingDirectory(): void { try { // Store the `process.cwd()` inside `VSCODE_CWD` @@ -71,10 +61,8 @@ setupCurrentWorkingDirectory(); * Add support for redirecting the loading of node modules * * Note: only applies when running out of sources. - * - * @param {string} injectPath */ -module.exports.devInjectNodeModuleLookupPath = function (injectPath) { +export function devInjectNodeModuleLookupPath(injectPath: string): void { if (!process.env['VSCODE_DEV']) { return; // only applies running out of sources } @@ -83,73 +71,43 @@ module.exports.devInjectNodeModuleLookupPath = function (injectPath) { throw new Error('Missing injectPath'); } - const Module = require('node:module'); - // ESM-uncomment-begin // register a loader hook + const Module = require('node:module'); Module.register('./bootstrap-import.js', { parentURL: import.meta.url, data: injectPath }); - // ESM-uncomment-end - // ESM-comment-begin - // const nodeModulesPath = path.join(__dirname, '../node_modules'); - // - // // @ts-ignore - // const originalResolveLookupPaths = Module._resolveLookupPaths; - // - // // @ts-ignore - // Module._resolveLookupPaths = function (moduleName, parent) { - // const paths = originalResolveLookupPaths(moduleName, parent); - // if (Array.isArray(paths)) { - // for (let i = 0, len = paths.length; i < len; i++) { - // if (paths[i] === nodeModulesPath) { - // paths.splice(i, 0, injectPath); - // break; - // } - // } - // } - // - // return paths; - // }; - // ESM-comment-end -}; +} -module.exports.removeGlobalNodeJsModuleLookupPaths = function () { +export function removeGlobalNodeJsModuleLookupPaths(): void { if (typeof process?.versions?.electron === 'string') { return; // Electron disables global search paths in https://github.com/electron/electron/blob/3186c2f0efa92d275dc3d57b5a14a60ed3846b0e/shell/common/node_bindings.cc#L653 } const Module = require('module'); - // @ts-ignore const globalPaths = Module.globalPaths; - // @ts-ignore const originalResolveLookupPaths = Module._resolveLookupPaths; - // @ts-ignore - Module._resolveLookupPaths = function (moduleName, parent) { + Module._resolveLookupPaths = function (moduleName: string, parent: any): string[] { const paths = originalResolveLookupPaths(moduleName, parent); if (Array.isArray(paths)) { let commonSuffixLength = 0; while (commonSuffixLength < paths.length && paths[paths.length - 1 - commonSuffixLength] === globalPaths[globalPaths.length - 1 - commonSuffixLength]) { commonSuffixLength++; } + return paths.slice(0, paths.length - commonSuffixLength); } + return paths; }; -}; +} /** * Helper to enable portable mode. - * - * @param {Partial} product - * @returns {{ portableDataPath: string; isPortable: boolean; }} */ -module.exports.configurePortable = function (product) { +export function configurePortable(product: Partial): { portableDataPath: string; isPortable: boolean } { const appRoot = path.dirname(__dirname); - /** - * @param {import('path')} path - */ - function getApplicationPath(path) { + function getApplicationPath(): string { if (process.env['VSCODE_DEV']) { return appRoot; } @@ -161,24 +119,20 @@ module.exports.configurePortable = function (product) { return path.dirname(path.dirname(appRoot)); } - /** - * @param {import('path')} path - */ - function getPortableDataPath(path) { + function getPortableDataPath(): string { if (process.env['VSCODE_PORTABLE']) { return process.env['VSCODE_PORTABLE']; } if (process.platform === 'win32' || process.platform === 'linux') { - return path.join(getApplicationPath(path), 'data'); + return path.join(getApplicationPath(), 'data'); } - // @ts-ignore const portableDataName = product.portable || `${product.applicationName}-portable-data`; - return path.join(path.dirname(getApplicationPath(path)), portableDataName); + return path.join(path.dirname(getApplicationPath()), portableDataName); } - const portableDataPath = getPortableDataPath(path); + const portableDataPath = getPortableDataPath(); const isPortable = !('target' in product) && fs.existsSync(portableDataPath); const portableTempPath = path.join(portableDataPath, 'tmp'); const isTempPortable = isPortable && fs.existsSync(portableTempPath); @@ -202,78 +156,4 @@ module.exports.configurePortable = function (product) { portableDataPath, isPortable }; -}; - -/** - * Helper to enable ASAR support. - */ -module.exports.enableASARSupport = function () { - // ESM-comment-begin - // const NODE_MODULES_PATH = path.join(__dirname, '../node_modules'); - // const NODE_MODULES_ASAR_PATH = `${NODE_MODULES_PATH}.asar`; - // - // // @ts-ignore - // const originalResolveLookupPaths = Module._resolveLookupPaths; - // - // // @ts-ignore - // Module._resolveLookupPaths = function (request, parent) { - // const paths = originalResolveLookupPaths(request, parent); - // if (Array.isArray(paths)) { - // for (let i = 0, len = paths.length; i < len; i++) { - // if (paths[i] === NODE_MODULES_PATH) { - // paths.splice(i, 0, NODE_MODULES_ASAR_PATH); - // break; - // } - // } - // } - // - // return paths; - // }; - // ESM-comment-end -}; - -/** - * Helper to convert a file path to a URI. - * - * TODO@bpasero TODO@esm check for removal once ESM has landed. - * - * @param {string} path - * @param {{ isWindows?: boolean, scheme?: string, fallbackAuthority?: string }} config - * @returns {string} - */ -module.exports.fileUriFromPath = function (path, config) { - - // Since we are building a URI, we normalize any backslash - // to slashes and we ensure that the path begins with a '/'. - let pathName = path.replace(/\\/g, '/'); - if (pathName.length > 0 && pathName.charAt(0) !== '/') { - pathName = `/${pathName}`; - } - - /** @type {string} */ - let uri; - - // Windows: in order to support UNC paths (which start with '//') - // that have their own authority, we do not use the provided authority - // but rather preserve it. - if (config.isWindows && pathName.startsWith('//')) { - uri = encodeURI(`${config.scheme || 'file'}:${pathName}`); - } - - // Otherwise we optionally add the provided authority if specified - else { - uri = encodeURI(`${config.scheme || 'file'}://${config.fallbackAuthority || ''}${pathName}`); - } - - return uri.replace(/#/g, '%23'); -}; - -//#endregion - -// ESM-uncomment-begin -export const devInjectNodeModuleLookupPath = module.exports.devInjectNodeModuleLookupPath; -export const removeGlobalNodeJsModuleLookupPaths = module.exports.removeGlobalNodeJsModuleLookupPaths; -export const configurePortable = module.exports.configurePortable; -export const enableASARSupport = module.exports.enableASARSupport; -export const fileUriFromPath = module.exports.fileUriFromPath; -// ESM-uncomment-end +} diff --git a/src/bootstrap-server.js b/src/bootstrap-server.ts similarity index 84% rename from src/bootstrap-server.js rename to src/bootstrap-server.ts index b84cc6a6ef629..d440e4195bd3e 100644 --- a/src/bootstrap-server.js +++ b/src/bootstrap-server.ts @@ -3,8 +3,5 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check -'use strict'; - -// Keep bootstrap-amd.js from redefining 'fs'. +// Keep bootstrap-esm.js from redefining 'fs'. delete process.env['ELECTRON_RUN_AS_NODE']; diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js deleted file mode 100644 index 9b5ed26e6c689..0000000000000 --- a/src/bootstrap-window.js +++ /dev/null @@ -1,345 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/// - -//@ts-check -'use strict'; - -/** - * @import { ISandboxConfiguration } from './vs/base/parts/sandbox/common/sandboxTypes' - * @typedef {any} LoaderConfig - */ - -/* eslint-disable no-restricted-globals */ - -(function (factory) { - // @ts-ignore - globalThis.MonacoBootstrapWindow = factory(); -}(function () { - const preloadGlobals = sandboxGlobals(); - const safeProcess = preloadGlobals.process; - - // increase number of stack frames(from 10, https://github.com/v8/v8/wiki/Stack-Trace-API) - Error.stackTraceLimit = 100; - - /** - * @param {string[]} modulePaths - * @param {(result: unknown, configuration: ISandboxConfiguration) => Promise | undefined} resultCallback - * @param {{ - * configureDeveloperSettings?: (config: ISandboxConfiguration) => { - * forceDisableShowDevtoolsOnError?: boolean, - * forceEnableDeveloperKeybindings?: boolean, - * disallowReloadKeybinding?: boolean, - * removeDeveloperKeybindingsAfterLoad?: boolean - * }, - * canModifyDOM?: (config: ISandboxConfiguration) => void, - * beforeLoaderConfig?: (loaderConfig: object) => void, - * beforeRequire?: (config: ISandboxConfiguration) => void - * }} [options] - */ - async function load(modulePaths, resultCallback, options) { - - // Await window configuration from preload - const timeout = setTimeout(() => { console.error(`[resolve window config] Could not resolve window configuration within 10 seconds, but will continue to wait...`); }, 10000); - performance.mark('code/willWaitForWindowConfig'); - /** @type {ISandboxConfiguration} */ - const configuration = await preloadGlobals.context.resolveConfiguration(); - performance.mark('code/didWaitForWindowConfig'); - clearTimeout(timeout); - - // Signal DOM modifications are now OK - if (typeof options?.canModifyDOM === 'function') { - options.canModifyDOM(configuration); - } - - // Developer settings - const { - forceEnableDeveloperKeybindings, - disallowReloadKeybinding, - removeDeveloperKeybindingsAfterLoad - } = typeof options?.configureDeveloperSettings === 'function' ? options.configureDeveloperSettings(configuration) : { - forceEnableDeveloperKeybindings: false, - disallowReloadKeybinding: false, - removeDeveloperKeybindingsAfterLoad: false - }; - const isDev = !!safeProcess.env['VSCODE_DEV']; - const enableDeveloperKeybindings = isDev || forceEnableDeveloperKeybindings; - /** - * @type {() => void | undefined} - */ - let developerDeveloperKeybindingsDisposable; - if (enableDeveloperKeybindings) { - developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding); - } - - globalThis._VSCODE_NLS_MESSAGES = configuration.nls.messages; - globalThis._VSCODE_NLS_LANGUAGE = configuration.nls.language; - let language = configuration.nls.language || 'en'; - if (language === 'zh-tw') { - language = 'zh-Hant'; - } else if (language === 'zh-cn') { - language = 'zh-Hans'; - } - - window.document.documentElement.setAttribute('lang', language); - - window['MonacoEnvironment'] = {}; - - // ESM-uncomment-begin - // Signal before require() - if (typeof options?.beforeRequire === 'function') { - options.beforeRequire(configuration); - } - - const baseUrl = new URL(`${fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out/`); - globalThis._VSCODE_FILE_ROOT = baseUrl.toString(); - - // DEV --------------------------------------------------------------------------------------- - // DEV: This is for development and enables loading CSS via import-statements via import-maps. - // DEV: For each CSS modules that we have we defined an entry in the import map that maps to - // DEV: a blob URL that loads the CSS via a dynamic @import-rule. - // DEV --------------------------------------------------------------------------------------- - if (Array.isArray(configuration.cssModules) && configuration.cssModules.length > 0) { - performance.mark('code/willAddCssLoader'); - - const style = document.createElement('style'); - style.type = 'text/css'; - style.media = 'screen'; - style.id = 'vscode-css-loading'; - document.head.appendChild(style); - - globalThis._VSCODE_CSS_LOAD = function (url) { - style.textContent += `@import url(${url});\n`; - }; - - /** - * @type { { imports: Record }} - */ - const importMap = { imports: {} }; - for (const cssModule of configuration.cssModules) { - const cssUrl = new URL(cssModule, baseUrl).href; - const jsSrc = `globalThis._VSCODE_CSS_LOAD('${cssUrl}');\n`; - const blob = new Blob([jsSrc], { type: 'application/javascript' }); - importMap.imports[cssUrl] = URL.createObjectURL(blob); - } - - const ttp = window.trustedTypes?.createPolicy('vscode-bootstrapImportMap', { createScript(value) { return value; }, }); - const importMapSrc = JSON.stringify(importMap, undefined, 2); - const importMapScript = document.createElement('script'); - importMapScript.type = 'importmap'; - importMapScript.setAttribute('nonce', '0c6a828f1297'); - // @ts-ignore - importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc; - document.head.appendChild(importMapScript); - - performance.mark('code/didAddCssLoader'); - } - - const result = Promise.all(modulePaths.map(modulePath => { - if (modulePath.includes('vs/css!')) { - // ESM/CSS when seeing the old `vs/css!` prefix we use that as a signal to - // load CSS via a tag - const cssModule = modulePath.replace('vs/css!', ''); - const link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = new URL(`${cssModule}.css`, baseUrl).href; - document.head.appendChild(link); - return Promise.resolve(); - - } else { - // ESM/JS module loading - return import(new URL(`${modulePath}.js`, baseUrl).href); - } - })); - - result.then((res) => invokeResult(res[0]), onUnexpectedError); - // ESM-uncomment-end - - // ESM-comment-begin - // /** @type {LoaderConfig} */ - // const loaderConfig = { - // baseUrl: `${fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out`, - // preferScriptTags: true - // }; - // - // // use a trusted types policy when loading via script tags - // loaderConfig.trustedTypesPolicy = window.trustedTypes?.createPolicy('amdLoader', { - // createScriptURL(value) { - // if (value.startsWith(window.location.origin)) { - // return value; - // } - // throw new Error(`Invalid script url: ${value}`); - // } - // }); - // - // // Teach the loader the location of the node modules we use in renderers - // // This will enable to load these modules via - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/code/browser/workbench/workbench-dev.html b/src/vs/code/browser/workbench/workbench-dev.html index be6d30bfb98cb..140030d8abeda 100644 --- a/src/vs/code/browser/workbench/workbench-dev.html +++ b/src/vs/code/browser/workbench/workbench-dev.html @@ -28,6 +28,7 @@ + @@ -35,31 +36,32 @@ - - + diff --git a/src/vs/code/browser/workbench/workbench.esm.html b/src/vs/code/browser/workbench/workbench.esm.html deleted file mode 100644 index 7788198273570..0000000000000 --- a/src/vs/code/browser/workbench/workbench.esm.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html index a4e95165cfbeb..7788198273570 100644 --- a/src/vs/code/browser/workbench/workbench.html +++ b/src/vs/code/browser/workbench/workbench.html @@ -25,7 +25,7 @@ - + @@ -33,38 +33,16 @@ - - - + - - - + + diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 2942951649663..ebf401ded8f35 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -1423,7 +1423,7 @@ export class CodeApplication extends Disposable { try { const argvContent = await this.fileService.readFile(this.environmentMainService.argvResource); const argvString = argvContent.value.toString(); - const argvJSON = parse(argvString); + const argvJSON = parse<{ 'enable-crash-reporter'?: boolean }>(argvString); const telemetryLevel = getTelemetryLevel(this.configurationService); const enableCrashReporter = telemetryLevel >= TelemetryLevel.CRASH; diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.esm.html b/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.esm.html deleted file mode 100644 index 19d194fc1c53e..0000000000000 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.esm.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - -
- - - - - - diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.html b/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.html index 5bdf62c823028..19d194fc1c53e 100644 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.html +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.html @@ -15,6 +15,8 @@ ; script-src 'self' + blob: + 'nonce-0c6a828f1297' ; style-src 'self' diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html b/src/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html deleted file mode 100644 index d274720295008..0000000000000 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - -
- - - - - diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer.html b/src/vs/code/electron-sandbox/processExplorer/processExplorer.html index 845d024e62608..d274720295008 100644 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorer.html +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer.html @@ -15,6 +15,8 @@ ; script-src 'self' + blob: + 'nonce-0c6a828f1297' ; style-src 'self' @@ -28,6 +30,7 @@ 'self' ; "> + @@ -35,5 +38,5 @@ - + diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer.js b/src/vs/code/electron-sandbox/processExplorer/processExplorer.js deleted file mode 100644 index 98e67e7c25c06..0000000000000 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorer.js +++ /dev/null @@ -1,47 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -(function () { - - /** - * @import { ISandboxConfiguration } from '../../../base/parts/sandbox/common/sandboxTypes' - */ - - const bootstrapWindow = bootstrapWindowLib(); - - // Load process explorer into window - bootstrapWindow.load(['vs/code/electron-sandbox/processExplorer/processExplorerMain'], function (processExplorer, configuration) { - return processExplorer.startup(configuration); - }, { - configureDeveloperSettings: function () { - return { - forceEnableDeveloperKeybindings: true - }; - }, - }); - - /** - * @returns {{ - * load: ( - * modules: string[], - * resultCallback: (result: any, configuration: ISandboxConfiguration) => unknown, - * options?: { - * configureDeveloperSettings?: (config: ISandboxConfiguration) => { - * forceEnableDeveloperKeybindings?: boolean, - * disallowReloadKeybinding?: boolean, - * removeDeveloperKeybindingsAfterLoad?: boolean - * } - * } - * ) => Promise - * }} - */ - function bootstrapWindowLib() { - // @ts-ignore (defined in bootstrap-window.js) - return window.MonacoBootstrapWindow; - } -}()); diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer.ts b/src/vs/code/electron-sandbox/processExplorer/processExplorer.ts new file mode 100644 index 0000000000000..11c86bbfe9236 --- /dev/null +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer.ts @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/* eslint-disable no-restricted-globals */ + +(function () { + + type IBootstrapWindow = import('vs/platform/window/electron-sandbox/window.js').IBootstrapWindow; + const bootstrapWindow: IBootstrapWindow = (window as any).MonacoBootstrapWindow; // defined by bootstrap-window.ts + + bootstrapWindow.load('vs/code/electron-sandbox/processExplorer/processExplorerMain', function (processExplorer, configuration) { + return processExplorer.startup(configuration); + }, { + configureDeveloperSettings: function () { + return { + forceEnableDeveloperKeybindings: true + }; + }, + }); +}()); diff --git a/src/vs/code/electron-sandbox/workbench/workbench-dev.esm.html b/src/vs/code/electron-sandbox/workbench/workbench-dev.esm.html deleted file mode 100644 index ea5cbee848a42..0000000000000 --- a/src/vs/code/electron-sandbox/workbench/workbench-dev.esm.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/vs/code/electron-sandbox/workbench/workbench-dev.html b/src/vs/code/electron-sandbox/workbench/workbench-dev.html index b1be2b7527cee..ea5cbee848a42 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench-dev.html +++ b/src/vs/code/electron-sandbox/workbench/workbench-dev.html @@ -28,6 +28,7 @@ 'self' 'unsafe-eval' blob: + 'nonce-0c6a828f1297' ; style-src 'self' @@ -48,6 +49,7 @@ 'script' ; trusted-types + vscode-bootstrapImportMap amdLoader cellRendererEditorText defaultWorkerFactory @@ -68,7 +70,6 @@ - diff --git a/src/vs/code/electron-sandbox/workbench/workbench.esm.html b/src/vs/code/electron-sandbox/workbench/workbench.esm.html deleted file mode 100644 index 1e89448e6056e..0000000000000 --- a/src/vs/code/electron-sandbox/workbench/workbench.esm.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/vs/code/electron-sandbox/workbench/workbench.html b/src/vs/code/electron-sandbox/workbench/workbench.html index eb525bd59f61c..c019f3d8913ac 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.html +++ b/src/vs/code/electron-sandbox/workbench/workbench.html @@ -62,11 +62,14 @@ tokenizeToString ; "/> + + + - + diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.ts similarity index 67% rename from src/vs/code/electron-sandbox/workbench/workbench.js rename to src/vs/code/electron-sandbox/workbench/workbench.ts index 0ddbcd49ba0c9..011514bdbfb7a 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.js +++ b/src/vs/code/electron-sandbox/workbench/workbench.ts @@ -3,18 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check -'use strict'; +/* eslint-disable no-restricted-globals */ (function () { - /** - * @import {INativeWindowConfiguration} from '../../../platform/window/common/window' - * @import {NativeParsedArgs} from '../../../platform/environment/common/argv' - * @import {ISandboxConfiguration} from '../../../base/parts/sandbox/common/sandboxTypes' - */ + type INativeWindowConfiguration = import('vs/platform/window/common/window.ts').INativeWindowConfiguration; + type NativeParsedArgs = import('vs/platform/environment/common/argv.js').NativeParsedArgs; + type IBootstrapWindow = import('vs/platform/window/electron-sandbox/window.js').IBootstrapWindow; + type IMainWindowSandboxGlobals = import('vs/base/parts/sandbox/electron-sandbox/globals.js').IMainWindowSandboxGlobals; - const bootstrapWindow = bootstrapWindowLib(); + const bootstrapWindow: IBootstrapWindow = (window as any).MonacoBootstrapWindow; // defined by bootstrap-window.ts + const preloadGlobals: IMainWindowSandboxGlobals = (window as any).vscode; // defined by preload.ts // Add a perf entry right from the top performance.mark('code/didStartRenderer'); @@ -23,10 +22,7 @@ // optimization to prevent a waterfall of loading to happen, because // we know for a fact that workbench.desktop.main will depend on // the related CSS counterpart. - bootstrapWindow.load([ - 'vs/workbench/workbench.desktop.main', - 'vs/css!vs/workbench/workbench.desktop.main' - ], + bootstrapWindow.load('vs/workbench/workbench.desktop.main', function (desktopMain, configuration) { // Mark start of workbench @@ -48,11 +44,7 @@ canModifyDOM: function (windowConfig) { showSplash(windowConfig); }, - beforeLoaderConfig: function (loaderConfig) { - // @ts-ignore - loaderConfig.recordStats = true; - }, - beforeRequire: function (windowConfig) { + beforeImport: function (windowConfig) { performance.mark('code/willLoadWorkbenchMain'); // Code windows have a `vscodeWindowId` property to identify them @@ -78,34 +70,7 @@ //#region Helpers - /** - * @returns {{ - * load: ( - * modules: string[], - * resultCallback: (result: any, configuration: INativeWindowConfiguration & NativeParsedArgs) => unknown, - * options?: { - * configureDeveloperSettings?: (config: INativeWindowConfiguration & NativeParsedArgs) => { - * forceDisableShowDevtoolsOnError?: boolean, - * forceEnableDeveloperKeybindings?: boolean, - * disallowReloadKeybinding?: boolean, - * removeDeveloperKeybindingsAfterLoad?: boolean - * }, - * canModifyDOM?: (config: INativeWindowConfiguration & NativeParsedArgs) => void, - * beforeLoaderConfig?: (loaderConfig: object) => void, - * beforeRequire?: (config: ISandboxConfiguration) => void - * } - * ) => Promise - * }} - */ - function bootstrapWindowLib() { - // @ts-ignore (defined in bootstrap-window.js) - return window.MonacoBootstrapWindow; - } - - /** - * @param {INativeWindowConfiguration & NativeParsedArgs} configuration - */ - function showSplash(configuration) { + function showSplash(configuration: INativeWindowConfiguration & NativeParsedArgs) { performance.mark('code/willShowPartsSplash'); let data = configuration.partsSplash; @@ -161,19 +126,17 @@ const style = document.createElement('style'); style.className = 'initialShellColors'; - document.head.appendChild(style); + window.document.head.appendChild(style); style.textContent = `body { - background-color: ${shellBackground}; - color: ${shellForeground}; - margin: 0; - padding: 0; - }`; + background-color: ${shellBackground}; + color: ${shellForeground}; + margin: 0; + padding: 0; + }`; // set zoom level as soon as possible - // @ts-ignore - if (typeof data?.zoomLevel === 'number' && typeof globalThis.vscode?.webFrame?.setZoomLevel === 'function') { - // @ts-ignore - globalThis.vscode.webFrame.setZoomLevel(data.zoomLevel); + if (typeof data?.zoomLevel === 'number' && typeof preloadGlobals?.webFrame?.setZoomLevel === 'function') { + preloadGlobals.webFrame.setZoomLevel(data.zoomLevel); } // restore parts if possible (we might not always store layout info) @@ -186,11 +149,11 @@ if (layoutInfo.windowBorder && colorInfo.windowBorder) { splash.setAttribute('style', ` - position: relative; - height: calc(100vh - 2px); - width: calc(100vw - 2px); - border: 1px solid var(--window-border-color); - `); + position: relative; + height: calc(100vh - 2px); + width: calc(100vw - 2px); + border: 1px solid var(--window-border-color); + `); splash.style.setProperty('--window-border-color', colorInfo.windowBorder); if (layoutInfo.windowBorderRadius) { @@ -204,51 +167,51 @@ // part: title const titleDiv = document.createElement('div'); titleDiv.setAttribute('style', ` - position: absolute; - width: 100%; - height: ${layoutInfo.titleBarHeight}px; - left: 0; - top: 0; - background-color: ${colorInfo.titleBarBackground}; - -webkit-app-region: drag; - `); + position: absolute; + width: 100%; + height: ${layoutInfo.titleBarHeight}px; + left: 0; + top: 0; + background-color: ${colorInfo.titleBarBackground}; + -webkit-app-region: drag; + `); splash.appendChild(titleDiv); if (colorInfo.titleBarBorder && layoutInfo.titleBarHeight > 0) { const titleBorder = document.createElement('div'); titleBorder.setAttribute('style', ` - position: absolute; - width: 100%; - height: 1px; - left: 0; - bottom: 0; - border-bottom: 1px solid ${colorInfo.titleBarBorder}; - `); + position: absolute; + width: 100%; + height: 1px; + left: 0; + bottom: 0; + border-bottom: 1px solid ${colorInfo.titleBarBorder}; + `); titleDiv.appendChild(titleBorder); } // part: activity bar const activityDiv = document.createElement('div'); activityDiv.setAttribute('style', ` - position: absolute; - width: ${layoutInfo.activityBarWidth}px; - height: calc(100% - ${layoutInfo.titleBarHeight + layoutInfo.statusBarHeight}px); - top: ${layoutInfo.titleBarHeight}px; - ${layoutInfo.sideBarSide}: 0; - background-color: ${colorInfo.activityBarBackground}; - `); + position: absolute; + width: ${layoutInfo.activityBarWidth}px; + height: calc(100% - ${layoutInfo.titleBarHeight + layoutInfo.statusBarHeight}px); + top: ${layoutInfo.titleBarHeight}px; + ${layoutInfo.sideBarSide}: 0; + background-color: ${colorInfo.activityBarBackground}; + `); splash.appendChild(activityDiv); if (colorInfo.activityBarBorder && layoutInfo.activityBarWidth > 0) { const activityBorderDiv = document.createElement('div'); activityBorderDiv.setAttribute('style', ` - position: absolute; - width: 1px; - height: 100%; - top: 0; - ${layoutInfo.sideBarSide === 'left' ? 'right' : 'left'}: 0; - ${layoutInfo.sideBarSide === 'left' ? 'border-right' : 'border-left'}: 1px solid ${colorInfo.activityBarBorder}; - `); + position: absolute; + width: 1px; + height: 100%; + top: 0; + ${layoutInfo.sideBarSide === 'left' ? 'right' : 'left'}: 0; + ${layoutInfo.sideBarSide === 'left' ? 'border-right' : 'border-left'}: 1px solid ${colorInfo.activityBarBorder}; + `); activityDiv.appendChild(activityBorderDiv); } @@ -257,26 +220,26 @@ if (configuration.workspace) { const sideDiv = document.createElement('div'); sideDiv.setAttribute('style', ` - position: absolute; - width: ${layoutInfo.sideBarWidth}px; - height: calc(100% - ${layoutInfo.titleBarHeight + layoutInfo.statusBarHeight}px); - top: ${layoutInfo.titleBarHeight}px; - ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; - background-color: ${colorInfo.sideBarBackground}; - `); + position: absolute; + width: ${layoutInfo.sideBarWidth}px; + height: calc(100% - ${layoutInfo.titleBarHeight + layoutInfo.statusBarHeight}px); + top: ${layoutInfo.titleBarHeight}px; + ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; + background-color: ${colorInfo.sideBarBackground}; + `); splash.appendChild(sideDiv); if (colorInfo.sideBarBorder && layoutInfo.sideBarWidth > 0) { const sideBorderDiv = document.createElement('div'); sideBorderDiv.setAttribute('style', ` - position: absolute; - width: 1px; - height: 100%; - top: 0; - right: 0; - ${layoutInfo.sideBarSide === 'left' ? 'right' : 'left'}: 0; - ${layoutInfo.sideBarSide === 'left' ? 'border-right' : 'border-left'}: 1px solid ${colorInfo.sideBarBorder}; - `); + position: absolute; + width: 1px; + height: 100%; + top: 0; + right: 0; + ${layoutInfo.sideBarSide === 'left' ? 'right' : 'left'}: 0; + ${layoutInfo.sideBarSide === 'left' ? 'border-right' : 'border-left'}: 1px solid ${colorInfo.sideBarBorder}; + `); sideDiv.appendChild(sideBorderDiv); } } @@ -284,28 +247,28 @@ // part: statusbar const statusDiv = document.createElement('div'); statusDiv.setAttribute('style', ` - position: absolute; - width: 100%; - height: ${layoutInfo.statusBarHeight}px; - bottom: 0; - left: 0; - background-color: ${configuration.workspace ? colorInfo.statusBarBackground : colorInfo.statusBarNoFolderBackground}; - `); + position: absolute; + width: 100%; + height: ${layoutInfo.statusBarHeight}px; + bottom: 0; + left: 0; + background-color: ${configuration.workspace ? colorInfo.statusBarBackground : colorInfo.statusBarNoFolderBackground}; + `); splash.appendChild(statusDiv); if (colorInfo.statusBarBorder && layoutInfo.statusBarHeight > 0) { const statusBorderDiv = document.createElement('div'); statusBorderDiv.setAttribute('style', ` - position: absolute; - width: 100%; - height: 1px; - top: 0; - border-top: 1px solid ${colorInfo.statusBarBorder}; - `); + position: absolute; + width: 100%; + height: 1px; + top: 0; + border-top: 1px solid ${colorInfo.statusBarBorder}; + `); statusDiv.appendChild(statusBorderDiv); } - document.body.appendChild(splash); + window.document.body.appendChild(splash); } performance.mark('code/didShowPartsSplash'); diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index b25377a804d32..57747be5577d0 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -58,7 +58,7 @@ export async function main(argv: string[]): Promise { const env: IProcessEnvironment = { ...process.env }; - // bootstrap-amd.js determines the electron environment based + // bootstrap-esm.js determines the electron environment based // on the following variable. For the server we need to unset // it to prevent importing any electron specific modules. // Refs https://github.com/microsoft/vscode/issues/221883 @@ -117,7 +117,7 @@ export async function main(argv: string[]): Promise { // Extensions Management else if (shouldSpawnCliProcess(args)) { - const cli = await import(['./cliProcessMain.js'].join('/') /* TODO@esm workaround to prevent esbuild from inlining this */); + const cli = await import(['./cliProcessMain.js'].join('/') /* workaround to prevent esbuild from inlining this */); await cli.main(args); return; @@ -397,10 +397,7 @@ export async function main(argv: string[]): Promise { return false; } if (target.type === 'page') { - return target.url.indexOf('workbench/workbench.html') > 0 || - target.url.indexOf('workbench/workbench-dev.html') > 0 || - target.url.indexOf('workbench/workbench.esm.html') > 0 || - target.url.indexOf('workbench/workbench-dev.esm.html') > 0; + return target.url.indexOf('workbench/workbench.html') > 0 || target.url.indexOf('workbench/workbench-dev.html') > 0; } else { return true; } diff --git a/src/vs/editor/browser/controller/editContext/native/nativeEditContext.css b/src/vs/editor/browser/controller/editContext/native/nativeEditContext.css index c4587dc89397c..7095c41aa93f5 100644 --- a/src/vs/editor/browser/controller/editContext/native/nativeEditContext.css +++ b/src/vs/editor/browser/controller/editContext/native/nativeEditContext.css @@ -15,12 +15,13 @@ .monaco-editor .edit-context-composition-none { background-color: transparent; + border-bottom: none; } .monaco-editor .edit-context-composition-secondary { - background-color: var(--vscode-editor-selectionBackground); + border-bottom: 1px solid var(--vscode-editor-compositionBorder); } .monaco-editor .edit-context-composition-primary { - background-color: var(--vscode-editor-selectionHighlightBackground); + border-bottom: 2px solid var(--vscode-editor-compositionBorder); } diff --git a/src/vs/editor/browser/services/treeSitter/treeSitterParserService.ts b/src/vs/editor/browser/services/treeSitter/treeSitterParserService.ts index a7eed4bdd12b2..c865456f6a2e4 100644 --- a/src/vs/editor/browser/services/treeSitter/treeSitterParserService.ts +++ b/src/vs/editor/browser/services/treeSitter/treeSitterParserService.ts @@ -15,11 +15,10 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet import { ILogService } from '../../../../platform/log/common/log.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { setTimeout0 } from '../../../../base/common/platform.js'; -import { importAMDNodeModule } from '../../../../amdX.js'; +import { canASAR, importAMDNodeModule } from '../../../../amdX.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { CancellationToken, cancelOnDispose } from '../../../../base/common/cancellation.js'; import { IEnvironmentService } from '../../../../platform/environment/common/environment.js'; -import { canASAR } from '../../../../base/common/amd.js'; import { CancellationError, isCancellationError } from '../../../../base/common/errors.js'; import { PromiseResult } from '../../../../base/common/observable.js'; import { Range } from '../../../common/core/range.js'; diff --git a/src/vs/editor/browser/view.ts b/src/vs/editor/browser/view.ts index b55cfa1e0c110..a094abf538c18 100644 --- a/src/vs/editor/browser/view.ts +++ b/src/vs/editor/browser/view.ts @@ -437,6 +437,7 @@ export class View extends ViewEventHandler { } this._contentWidgets.overflowingContentWidgetsDomNode.domNode.remove(); + this._overlayWidgets.overflowingOverlayWidgetsDomNode.domNode.remove(); this._context.removeEventHandler(this); this._viewGpuContext?.dispose(); diff --git a/src/vs/editor/browser/viewParts/selections/selections.ts b/src/vs/editor/browser/viewParts/selections/selections.ts index ce07d7984fa71..a882f80f4f142 100644 --- a/src/vs/editor/browser/viewParts/selections/selections.ts +++ b/src/vs/editor/browser/viewParts/selections/selections.ts @@ -56,6 +56,9 @@ function toStyled(item: LineVisibleRanges): LineVisibleRangesWithStyle { return new LineVisibleRangesWithStyle(item.lineNumber, item.ranges.map(toStyledRange)); } +/** + * This view part displays selected text to the user. Every line has its own selection overlay. + */ export class SelectionsOverlay extends DynamicViewOverlay { private static readonly SELECTION_CLASS_NAME = 'selected-text'; diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index ff8bbb85464b9..2432a8f657acb 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -32,13 +32,6 @@ import { FindSectionHeaderOptions, SectionHeader, findSectionHeaders } from './f import { IRawModelData, IWorkerTextModelSyncChannelServer } from './textModelSync/textModelSync.protocol.js'; import { ICommonModel, WorkerTextModelSyncServer } from './textModelSync/textModelSync.impl.js'; -// ESM-comment-begin -// const isESM = false; -// ESM-comment-end -// ESM-uncomment-begin -const isESM = true; -// ESM-uncomment-end - export interface IMirrorModel extends IMirrorTextModel { readonly uri: URI; readonly version: number; @@ -565,12 +558,8 @@ export class EditorSimpleWorker extends BaseEditorSimpleWorker { resolve(getAllMethodNames(this._foreignModule)); }; - if (!isESM) { - require([`${moduleId}`], onModuleCallback, reject); - } else { - const url = FileAccess.asBrowserUri(`${moduleId}.js` as AppResourcePath).toString(true); - import(`${url}`).then(onModuleCallback).catch(reject); - } + const url = FileAccess.asBrowserUri(`${moduleId}.js` as AppResourcePath).toString(true); + import(`${url}`).then(onModuleCallback).catch(reject); }); } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 0c4cf7598cc44..b49b11c86872f 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -230,6 +230,7 @@ export class MenuId { static readonly ChatInlineResourceAnchorContext = new MenuId('ChatInlineResourceAnchorContext'); static readonly ChatInlineSymbolAnchorContext = new MenuId('ChatInlineSymbolAnchorContext'); static readonly ChatCommandCenter = new MenuId('ChatCommandCenter'); + static readonly ChatAttachmentsContext = new MenuId('ChatAttachmentsContext'); static readonly AccessibleView = new MenuId('AccessibleView'); static readonly MultiDiffEditorFileToolbar = new MenuId('MultiDiffEditorFileToolbar'); static readonly DiffEditorHunkToolbar = new MenuId('DiffEditorHunkToolbar'); diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 5b7a51dced270..400ae1033cb92 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -296,6 +296,7 @@ export class ConfigurationModel implements IConfigurationModel { } export interface ConfigurationParseOptions { + skipUnregistered?: boolean; scopes?: ConfigurationScope[]; skipRestricted?: boolean; include?: string[]; @@ -428,14 +429,10 @@ export class ConfigurationModelParser { restricted.push(...result.restricted); } else { const propertySchema = configurationProperties[key]; - const scope = propertySchema ? typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW : undefined; if (propertySchema?.restricted) { restricted.push(key); } - if (!options.exclude?.includes(key) /* Check exclude */ - && (options.include?.includes(key) /* Check include */ - || ((scope === undefined || options.scopes === undefined || options.scopes.includes(scope)) /* Check scopes */ - && !(options.skipRestricted && propertySchema?.restricted)))) /* Check restricted */ { + if (this.shouldInclude(key, propertySchema, options)) { raw[key] = properties[key]; } else { hasExcludedProperties = true; @@ -445,6 +442,31 @@ export class ConfigurationModelParser { return { raw, restricted, hasExcludedProperties }; } + private shouldInclude(key: string, propertySchema: IConfigurationPropertySchema | undefined, options: ConfigurationParseOptions): boolean { + if (options.exclude?.includes(key)) { + return false; + } + + if (options.include?.includes(key)) { + return true; + } + + if (options.skipRestricted && propertySchema?.restricted) { + return false; + } + + if (options.skipUnregistered && !propertySchema) { + return false; + } + + const scope = propertySchema ? typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW : undefined; + if (scope === undefined || options.scopes === undefined) { + return true; + } + + return options.scopes.includes(scope); + } + private toOverrides(raw: any, conflictReporter: (message: string) => void): IOverrides[] { const overrides: IOverrides[] = []; for (const key of Object.keys(raw)) { diff --git a/src/vs/platform/cssDev/node/cssDevService.ts b/src/vs/platform/cssDev/node/cssDevService.ts index 6c24e8e0672c6..5aa1efa6e39e6 100644 --- a/src/vs/platform/cssDev/node/cssDevService.ts +++ b/src/vs/platform/cssDev/node/cssDevService.ts @@ -5,7 +5,6 @@ import { spawn } from 'child_process'; import { relative } from 'path'; -import { isESM } from '../../../base/common/amd.js'; import { FileAccess } from '../../../base/common/network.js'; import { StopWatch } from '../../../base/common/stopwatch.js'; import { IEnvironmentService } from '../../environment/common/environment.js'; @@ -32,7 +31,7 @@ export class CSSDevelopmentService implements ICSSDevelopmentService { ) { } get isEnabled(): boolean { - return !this.envService.isBuilt && isESM; + return !this.envService.isBuilt; } getCssModules(): Promise { diff --git a/src/vs/platform/environment/node/stdin.ts b/src/vs/platform/environment/node/stdin.ts index b0e0cd60c64b4..c3ecd62f9535a 100644 --- a/src/vs/platform/environment/node/stdin.ts +++ b/src/vs/platform/environment/node/stdin.ts @@ -41,12 +41,12 @@ export function getStdinFilePath(): string { export async function readFromStdin(targetPath: string, verbose: boolean, onEnd?: Function): Promise { let [encoding, iconv] = await Promise.all([ - resolveTerminalEncoding(verbose), // respect terminal encoding when piping into file - import('@vscode/iconv-lite-umd'), // lazy load encoding module for usage - fs.promises.appendFile(targetPath, '') // make sure file exists right away (https://github.com/microsoft/vscode/issues/155341) + resolveTerminalEncoding(verbose), // respect terminal encoding when piping into file + import('@vscode/iconv-lite-umd'), // lazy load encoding module for usage + fs.promises.appendFile(targetPath, '') // make sure file exists right away (https://github.com/microsoft/vscode/issues/155341) ]); - if (!iconv.encodingExists(encoding)) { + if (!iconv.default.encodingExists(encoding)) { console.log(`Unsupported terminal encoding: ${encoding}, falling back to UTF-8.`); encoding = 'utf8'; } @@ -59,7 +59,7 @@ export async function readFromStdin(targetPath: string, verbose: boolean, onEnd? const appendFileQueue = new Queue(); - const decoder = iconv.getDecoder(encoding); + const decoder = iconv.default.getDecoder(encoding); process.stdin.on('data', chunk => { const chunkStr = decoder.write(chunk); diff --git a/src/vs/platform/environment/node/userDataPath.d.ts b/src/vs/platform/environment/node/userDataPath.d.ts deleted file mode 100644 index c75b432c59c71..0000000000000 --- a/src/vs/platform/environment/node/userDataPath.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; - -/** - * Returns the user data path to use with some rules: - * - respect portable mode - * - respect VSCODE_APPDATA environment variable - * - respect --user-data-dir CLI argument - */ -export function getUserDataPath(args: NativeParsedArgs, productName: string): string; diff --git a/src/vs/platform/environment/node/userDataPath.js b/src/vs/platform/environment/node/userDataPath.js deleted file mode 100644 index fb023fff3c700..0000000000000 --- a/src/vs/platform/environment/node/userDataPath.js +++ /dev/null @@ -1,148 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/// - -//@ts-check -'use strict'; - -// ESM-uncomment-begin -import * as os from 'os'; -import * as path from 'path'; - -/** @type any */ -const module = { exports: {} }; -// ESM-uncomment-end - -(function () { - // ESM-comment-begin - // const isESM = false; - // ESM-comment-end - // ESM-uncomment-begin - const isESM = true; - // ESM-uncomment-end - - /** - * @import { NativeParsedArgs } from '../../environment/common/argv' - */ - - /** - * @param {typeof import('path')} path - * @param {typeof import('os')} os - * @param {string} cwd - */ - function factory(path, os, cwd) { - - /** - * @param {NativeParsedArgs} cliArgs - * @param {string} productName - * - * @returns {string} - */ - function getUserDataPath(cliArgs, productName) { - const userDataPath = doGetUserDataPath(cliArgs, productName); - const pathsToResolve = [userDataPath]; - - // If the user-data-path is not absolute, make - // sure to resolve it against the passed in - // current working directory. We cannot use the - // node.js `path.resolve()` logic because it will - // not pick up our `VSCODE_CWD` environment variable - // (https://github.com/microsoft/vscode/issues/120269) - if (!path.isAbsolute(userDataPath)) { - pathsToResolve.unshift(cwd); - } - - return path.resolve(...pathsToResolve); - } - - /** - * @param {NativeParsedArgs} cliArgs - * @param {string} productName - * - * @returns {string} - */ - function doGetUserDataPath(cliArgs, productName) { - - // 0. Running out of sources has a fixed productName - if (process.env['VSCODE_DEV']) { - productName = 'code-oss-dev'; - } - - // 1. Support portable mode - const portablePath = process.env['VSCODE_PORTABLE']; - if (portablePath) { - return path.join(portablePath, 'user-data'); - } - - // 2. Support global VSCODE_APPDATA environment variable - let appDataPath = process.env['VSCODE_APPDATA']; - if (appDataPath) { - return path.join(appDataPath, productName); - } - - // With Electron>=13 --user-data-dir switch will be propagated to - // all processes https://github.com/electron/electron/blob/1897b14af36a02e9aa7e4d814159303441548251/shell/browser/electron_browser_client.cc#L546-L553 - // Check VSCODE_PORTABLE and VSCODE_APPDATA before this case to get correct values. - // 3. Support explicit --user-data-dir - const cliPath = cliArgs['user-data-dir']; - if (cliPath) { - return cliPath; - } - - // 4. Otherwise check per platform - switch (process.platform) { - case 'win32': - appDataPath = process.env['APPDATA']; - if (!appDataPath) { - const userProfile = process.env['USERPROFILE']; - if (typeof userProfile !== 'string') { - throw new Error('Windows: Unexpected undefined %USERPROFILE% environment variable'); - } - - appDataPath = path.join(userProfile, 'AppData', 'Roaming'); - } - break; - case 'darwin': - appDataPath = path.join(os.homedir(), 'Library', 'Application Support'); - break; - case 'linux': - appDataPath = process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config'); - break; - default: - throw new Error('Platform not supported'); - } - - return path.join(appDataPath, productName); - } - - return { - getUserDataPath - }; - } - - if (!isESM && typeof define === 'function') { - define(['path', 'os', 'vs/base/common/process'], function ( - /** @type {typeof import('path')} */ path, - /** @type {typeof import('os')} */ os, - /** @type {typeof import("../../../base/common/process")} */ process - ) { - return factory(path, os, process.cwd()); // amd - }); - } else if (typeof module === 'object' && typeof module.exports === 'object') { - // ESM-comment-begin - // const path = require('path'); - // const os = require('os'); - // ESM-comment-end - - module.exports = factory(path, os, process.env['VSCODE_CWD'] || process.cwd()); // commonjs - } else { - throw new Error('Unknown context'); - } -}()); - -// ESM-uncomment-begin -export const getUserDataPath = module.exports.getUserDataPath; -// ESM-uncomment-end diff --git a/src/vs/platform/environment/node/userDataPath.ts b/src/vs/platform/environment/node/userDataPath.ts new file mode 100644 index 0000000000000..27190b2b84b89 --- /dev/null +++ b/src/vs/platform/environment/node/userDataPath.ts @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as os from 'os'; +import * as path from 'path'; +import { NativeParsedArgs } from '../common/argv.js'; + +const cwd = process.env['VSCODE_CWD'] || process.cwd(); + +/** + * Returns the user data path to use with some rules: + * - respect portable mode + * - respect VSCODE_APPDATA environment variable + * - respect --user-data-dir CLI argument + */ +export function getUserDataPath(cliArgs: NativeParsedArgs, productName: string): string { + const userDataPath = doGetUserDataPath(cliArgs, productName); + const pathsToResolve = [userDataPath]; + + // If the user-data-path is not absolute, make + // sure to resolve it against the passed in + // current working directory. We cannot use the + // node.js `path.resolve()` logic because it will + // not pick up our `VSCODE_CWD` environment variable + // (https://github.com/microsoft/vscode/issues/120269) + if (!path.isAbsolute(userDataPath)) { + pathsToResolve.unshift(cwd); + } + + return path.resolve(...pathsToResolve); +} + +function doGetUserDataPath(cliArgs: NativeParsedArgs, productName: string): string { + + // 0. Running out of sources has a fixed productName + if (process.env['VSCODE_DEV']) { + productName = 'code-oss-dev'; + } + + // 1. Support portable mode + const portablePath = process.env['VSCODE_PORTABLE']; + if (portablePath) { + return path.join(portablePath, 'user-data'); + } + + // 2. Support global VSCODE_APPDATA environment variable + let appDataPath = process.env['VSCODE_APPDATA']; + if (appDataPath) { + return path.join(appDataPath, productName); + } + + // With Electron>=13 --user-data-dir switch will be propagated to + // all processes https://github.com/electron/electron/blob/1897b14af36a02e9aa7e4d814159303441548251/shell/browser/electron_browser_client.cc#L546-L553 + // Check VSCODE_PORTABLE and VSCODE_APPDATA before this case to get correct values. + // 3. Support explicit --user-data-dir + const cliPath = cliArgs['user-data-dir']; + if (cliPath) { + return cliPath; + } + + // 4. Otherwise check per platform + switch (process.platform) { + case 'win32': + appDataPath = process.env['APPDATA']; + if (!appDataPath) { + const userProfile = process.env['USERPROFILE']; + if (typeof userProfile !== 'string') { + throw new Error('Windows: Unexpected undefined %USERPROFILE% environment variable'); + } + + appDataPath = path.join(userProfile, 'AppData', 'Roaming'); + } + break; + case 'darwin': + appDataPath = path.join(os.homedir(), 'Library', 'Application Support'); + break; + case 'linux': + appDataPath = process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config'); + break; + default: + throw new Error('Platform not supported'); + } + + return path.join(appDataPath, productName); +} diff --git a/src/vs/platform/environment/test/node/nativeModules.integrationTest.ts b/src/vs/platform/environment/test/node/nativeModules.integrationTest.ts index 95aa93b861759..3b08a22c1d058 100644 --- a/src/vs/platform/environment/test/node/nativeModules.integrationTest.ts +++ b/src/vs/platform/environment/test/node/nativeModules.integrationTest.ts @@ -107,32 +107,17 @@ flakySuite('Native Modules (all platforms)', () => { }); test('@vscode/sqlite3', async () => { - // ESM-comment-begin - // const sqlite3 = await import('@vscode/sqlite3'); - // ESM-comment-end - // ESM-uncomment-begin const { default: sqlite3 } = await import('@vscode/sqlite3'); - // ESM-uncomment-end assert.ok(typeof sqlite3.Database === 'function', testErrorMessage('@vscode/sqlite3')); }); test('http-proxy-agent', async () => { - // ESM-comment-begin - // const mod = await import('http-proxy-agent'); - // ESM-comment-end - // ESM-uncomment-begin const { default: mod } = await import('http-proxy-agent'); - // ESM-uncomment-end assert.ok(typeof mod.HttpProxyAgent === 'function', testErrorMessage('http-proxy-agent')); }); test('https-proxy-agent', async () => { - // ESM-comment-begin - // const mod = await import('https-proxy-agent'); - // ESM-comment-end - // ESM-uncomment-begin const { default: mod } = await import('https-proxy-agent'); - // ESM-uncomment-end assert.ok(typeof mod.HttpsProxyAgent === 'function', testErrorMessage('https-proxy-agent')); }); diff --git a/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts b/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts index e342fb4d2e263..9af60c96ddcd9 100644 --- a/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts +++ b/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { importAMDNodeModule } from '../../../amdX.js'; import { getErrorMessage } from '../../../base/common/errors.js'; import { TargetPlatform } from '../../extensions/common/extensions.js'; import { createDecorator } from '../../instantiation/common/instantiation.js'; @@ -67,15 +66,8 @@ export class ExtensionSignatureVerificationService implements IExtensionSignatur } private async resolveVsceSign(): Promise { - // ESM-uncomment-begin - if (typeof importAMDNodeModule === 'function') { /* fixes unused import, remove me */ } const mod = '@vscode/vsce-sign'; return import(mod); - // ESM-uncomment-end - - // ESM-comment-begin - // return importAMDNodeModule('@vscode/vsce-sign', 'src/main.js'); - // ESM-comment-end } public async verify(extensionId: string, version: string, vsixFilePath: string, signatureArchiveFilePath: string, clientTargetPlatform?: TargetPlatform): Promise { diff --git a/src/vs/platform/files/node/watcher/watcherClient.ts b/src/vs/platform/files/node/watcher/watcherClient.ts index f14e8c4dd8ef5..b88b7f3200480 100644 --- a/src/vs/platform/files/node/watcher/watcherClient.ts +++ b/src/vs/platform/files/node/watcher/watcherClient.ts @@ -32,7 +32,7 @@ export class UniversalWatcherClient extends AbstractUniversalWatcherClient { serverName: 'File Watcher', args: ['--type=fileWatcher'], env: { - VSCODE_AMD_ENTRYPOINT: 'vs/platform/files/node/watcher/watcherMain', + VSCODE_ESM_ENTRYPOINT: 'vs/platform/files/node/watcher/watcherMain', VSCODE_PIPE_LOGGING: 'true', VSCODE_VERBOSE_LOGGING: 'true' // transmit console logs from server to client } diff --git a/src/vs/platform/files/test/node/diskFileService.integrationTest.ts b/src/vs/platform/files/test/node/diskFileService.integrationTest.ts index 84f4a01c3af6e..38d1af9be8f78 100644 --- a/src/vs/platform/files/test/node/diskFileService.integrationTest.ts +++ b/src/vs/platform/files/test/node/diskFileService.integrationTest.ts @@ -20,7 +20,6 @@ import { etag, IFileAtomicReadOptions, FileOperation, FileOperationError, FileOp import { FileService } from '../../common/fileService.js'; import { DiskFileSystemProvider } from '../../node/diskFileSystemProvider.js'; import { NullLogService } from '../../../log/common/log.js'; -import { isESM } from '../../../../base/common/amd.js'; function getByName(root: IFileStat, name: string): IFileStat | undefined { if (root.children === undefined) { @@ -132,7 +131,7 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider { DiskFileSystemProvider.configureFlushOnWrite(false); // speed up all unit tests by disabling flush on write -(!isESM ? suite.skip : flakySuite /* somehow fails in AMD with ENOENT for fixtures dir */)('Disk File Service', function () { +flakySuite('Disk File Service', function () { const testSchema = 'test'; diff --git a/src/vs/platform/issue/electron-main/issueMainService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts index 00a203c2d412b..7d1c7d5e8ac12 100644 --- a/src/vs/platform/issue/electron-main/issueMainService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -22,7 +22,6 @@ import { IIPCObjectUrl, IProtocolMainService } from '../../protocol/electron-mai import { zoomLevelToZoomFactor } from '../../window/common/window.js'; import { ICodeWindow, IWindowState } from '../../window/electron-main/window.js'; import { IWindowsMainService } from '../../windows/electron-main/windows.js'; -import { isESM } from '../../../base/common/amd.js'; import { ICSSDevelopmentService } from '../../cssDev/node/cssDevService.js'; interface IBrowserWindowOptions { @@ -93,7 +92,7 @@ export class IssueMainService implements IIssueMainService { }); this.issueReporterWindow.loadURL( - FileAccess.asBrowserUri(`vs/workbench/contrib/issue/electron-sandbox/issueReporter${this.environmentMainService.isBuilt ? '' : '-dev'}.${isESM ? 'esm.' : ''}html`).toString(true) + FileAccess.asBrowserUri(`vs/workbench/contrib/issue/electron-sandbox/issueReporter${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true) ); this.issueReporterWindow.on('close', () => { diff --git a/src/vs/platform/issue/electron-main/processMainService.ts b/src/vs/platform/issue/electron-main/processMainService.ts index dd2a275ee10dc..2dec13f76e306 100644 --- a/src/vs/platform/issue/electron-main/processMainService.ts +++ b/src/vs/platform/issue/electron-main/processMainService.ts @@ -26,7 +26,6 @@ import { IStateService } from '../../state/node/state.js'; import { UtilityProcess } from '../../utilityProcess/electron-main/utilityProcess.js'; import { zoomLevelToZoomFactor } from '../../window/common/window.js'; import { IWindowState } from '../../window/electron-main/window.js'; -import { isESM } from '../../../base/common/amd.js'; const processExplorerWindowState = 'issue.processExplorerWindowState'; @@ -165,7 +164,7 @@ export class ProcessMainService implements IProcessMainService { }); this.processExplorerWindow.loadURL( - FileAccess.asBrowserUri(`vs/code/electron-sandbox/processExplorer/processExplorer${this.environmentMainService.isBuilt ? '' : '-dev'}.${isESM ? 'esm.' : ''}html`).toString(true) + FileAccess.asBrowserUri(`vs/code/electron-sandbox/processExplorer/processExplorer${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true) ); this.processExplorerWindow.on('close', () => { diff --git a/src/vs/platform/protocol/electron-main/protocolMainService.ts b/src/vs/platform/protocol/electron-main/protocolMainService.ts index 840b936d376e9..5f666fe4f733d 100644 --- a/src/vs/platform/protocol/electron-main/protocolMainService.ts +++ b/src/vs/platform/protocol/electron-main/protocolMainService.ts @@ -97,7 +97,7 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ let headers: Record | undefined; if (this.environmentService.crossOriginIsolated) { const pathBasename = basename(path); - if (pathBasename === 'workbench.html' || pathBasename === 'workbench-dev.html' || pathBasename === 'workbench.esm.html' || pathBasename === 'workbench-dev.esm.html') { + if (pathBasename === 'workbench.html' || pathBasename === 'workbench-dev.html') { headers = COI.CoopAndCoep; } else { headers = COI.getHeadersFromQuery(request.url); diff --git a/src/vs/platform/request/node/proxy.ts b/src/vs/platform/request/node/proxy.ts index 5f1d40109a2cb..a87fb31a9382e 100644 --- a/src/vs/platform/request/node/proxy.ts +++ b/src/vs/platform/request/node/proxy.ts @@ -45,20 +45,10 @@ export async function getProxyAgent(rawRequestURL: string, env: typeof process.e }; if (requestURL.protocol === 'http:') { - // ESM-comment-begin - // const mod = await import('http-proxy-agent'); - // ESM-comment-end - // ESM-uncomment-begin const { default: mod } = await import('http-proxy-agent'); - // ESM-uncomment-end return new mod.HttpProxyAgent(proxyURL, opts); } else { - // ESM-comment-begin - // const mod = await import('https-proxy-agent'); - // ESM-comment-end - // ESM-uncomment-begin const { default: mod } = await import('https-proxy-agent'); - // ESM-uncomment-end return new mod.HttpsProxyAgent(proxyURL, opts); } } diff --git a/src/vs/platform/sign/browser/signService.ts b/src/vs/platform/sign/browser/signService.ts index f262154198703..ec1e11bdd94f4 100644 --- a/src/vs/platform/sign/browser/signService.ts +++ b/src/vs/platform/sign/browser/signService.ts @@ -6,9 +6,7 @@ import { importAMDNodeModule, resolveAmdNodeModulePath } from '../../../amdX.js'; import { WindowIntervalTimer } from '../../../base/browser/dom.js'; import { mainWindow } from '../../../base/browser/window.js'; -import { isESM } from '../../../base/common/amd.js'; import { memoize } from '../../../base/common/decorators.js'; -import { FileAccess } from '../../../base/common/network.js'; import { IProductService } from '../../product/common/productService.js'; import { AbstractSignService, IVsdaValidator } from '../common/abstractSignService.js'; import { ISignService } from '../common/sign.js'; @@ -88,9 +86,7 @@ export class SignService extends AbstractSignService implements ISignService { } private async getWasmBytes(): Promise { - const url = isESM - ? resolveAmdNodeModulePath('vsda', 'rust/web/vsda_bg.wasm') - : FileAccess.asBrowserUri('vsda/../vsda_bg.wasm').toString(true); + const url = resolveAmdNodeModulePath('vsda', 'rust/web/vsda_bg.wasm'); const response = await fetch(url); if (!response.ok) { throw new Error('error loading vsda'); diff --git a/src/vs/platform/sign/node/signService.ts b/src/vs/platform/sign/node/signService.ts index a89a45edcb3e5..654ac856a2069 100644 --- a/src/vs/platform/sign/node/signService.ts +++ b/src/vs/platform/sign/node/signService.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { importAMDNodeModule } from '../../../amdX.js'; import { AbstractSignService, IVsdaValidator } from '../common/abstractSignService.js'; import { ISignService } from '../common/sign.js'; @@ -30,15 +29,8 @@ export class SignService extends AbstractSignService implements ISignService { } private async vsda(): Promise { - // ESM-uncomment-begin - if (typeof importAMDNodeModule === 'function') { /* fixes unused import, remove me */ } const mod = 'vsda'; const { default: vsda } = await import(mod); return vsda; - // ESM-uncomment-end - - // ESM-comment-begin - // return importAMDNodeModule('vsda', 'index.js'); - // ESM-comment-end } } diff --git a/src/vs/platform/telemetry/common/1dsAppender.ts b/src/vs/platform/telemetry/common/1dsAppender.ts index bddf9da2530ee..7efb786c7630c 100644 --- a/src/vs/platform/telemetry/common/1dsAppender.ts +++ b/src/vs/platform/telemetry/common/1dsAppender.ts @@ -23,17 +23,10 @@ const endpointUrl = 'https://mobile.events.data.microsoft.com/OneCollector/1.0'; const endpointHealthUrl = 'https://mobile.events.data.microsoft.com/ping'; async function getClient(instrumentationKey: string, addInternalFlag?: boolean, xhrOverride?: IXHROverride): Promise { - // ESM-comment-begin - // if (isWeb) { /* fix the import warning */ } - // const oneDs = await importAMDNodeModule('@microsoft/1ds-core-js', 'dist/ms.core.js'); - // const postPlugin = await importAMDNodeModule('@microsoft/1ds-post-js', 'dist/ms.post.js'); - // ESM-comment-end - // ESM-uncomment-begin // eslint-disable-next-line local/code-amd-node-module const oneDs = isWeb ? await importAMDNodeModule('@microsoft/1ds-core-js', 'bundle/ms.core.min.js') : await import('@microsoft/1ds-core-js'); // eslint-disable-next-line local/code-amd-node-module const postPlugin = isWeb ? await importAMDNodeModule('@microsoft/1ds-post-js', 'bundle/ms.post.min.js') : await import('@microsoft/1ds-post-js'); - // ESM-uncomment-end const appInsightsCore = new oneDs.AppInsightsCore(); const collectorChannelPlugin: PostChannel = new postPlugin.PostChannel(); diff --git a/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts b/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts index 894ff8cca30e9..233b79f96b131 100644 --- a/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts +++ b/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts @@ -43,7 +43,7 @@ export class CustomEndpointTelemetryService implements ICustomEndpointTelemetryS env: { ELECTRON_RUN_AS_NODE: 1, VSCODE_PIPE_LOGGING: 'true', - VSCODE_AMD_ENTRYPOINT: 'vs/workbench/contrib/debug/node/telemetryApp' + VSCODE_ESM_ENTRYPOINT: 'vs/workbench/contrib/debug/node/telemetryApp' } } ); diff --git a/src/vs/platform/terminal/electron-main/electronPtyHostStarter.ts b/src/vs/platform/terminal/electron-main/electronPtyHostStarter.ts index 607bd9b3a377e..d4835c5879f0b 100644 --- a/src/vs/platform/terminal/electron-main/electronPtyHostStarter.ts +++ b/src/vs/platform/terminal/electron-main/electronPtyHostStarter.ts @@ -85,7 +85,7 @@ export class ElectronPtyHostStarter extends Disposable implements IPtyHostStarte this._environmentMainService.unsetSnapExportedVariables(); const config: { [key: string]: string } = { ...deepClone(process.env), - VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', + VSCODE_ESM_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', VSCODE_PIPE_LOGGING: 'true', VSCODE_VERBOSE_LOGGING: 'true', // transmit console logs from server to client, VSCODE_RECONNECT_GRACE_TIME: String(this._reconnectConstants.graceTime), diff --git a/src/vs/platform/terminal/node/nodePtyHostStarter.ts b/src/vs/platform/terminal/node/nodePtyHostStarter.ts index bc78aa5d8a688..707f1ca887b4f 100644 --- a/src/vs/platform/terminal/node/nodePtyHostStarter.ts +++ b/src/vs/platform/terminal/node/nodePtyHostStarter.ts @@ -24,7 +24,7 @@ export class NodePtyHostStarter extends Disposable implements IPtyHostStarter { serverName: 'Pty Host', args: ['--type=ptyHost', '--logsPath', this._environmentService.logsHome.with({ scheme: Schemas.file }).fsPath], env: { - VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', + VSCODE_ESM_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', VSCODE_PIPE_LOGGING: 'true', VSCODE_VERBOSE_LOGGING: 'true', // transmit console logs from server to client, VSCODE_RECONNECT_GRACE_TIME: this._reconnectConstants.graceTime, diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 53dcb6871040e..78b55d83c794f 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -31,14 +31,9 @@ import { IProductService } from '../../product/common/productService.js'; import { join } from 'path'; import { memoize } from '../../../base/common/decorators.js'; import * as performance from '../../../base/common/performance.js'; -// ESM-comment-begin -// import { Terminal as XtermTerminal } from '@xterm/headless'; -// ESM-comment-end -// ESM-uncomment-begin import pkg from '@xterm/headless'; type XtermTerminal = pkg.Terminal; const { Terminal: XtermTerminal } = pkg; -// ESM-uncomment-end export function traceRpc(_target: any, key: string, descriptor: any) { if (typeof descriptor.value !== 'function') { diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index 3435742e5f582..d7a470d5bf6e1 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -50,7 +50,7 @@ const enum Constants { */ KillSpawnThrottleInterval = 250, /** - * The amount of time to wait when a call is throttles beyond the exact amount, this is used to + * The amount of time to wait when a call is throttled beyond the exact amount, this is used to * try prevent early timeouts causing a kill/spawn call to happen at double the regular * interval. */ @@ -388,6 +388,10 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess if (!isWindows || !('useConpty' in this._ptyOptions) || !this._ptyOptions.useConpty) { return; } + // Don't throttle when using conpty.dll as it seems to have been fixed in later versions + if (this._ptyOptions.useConptyDll) { + return; + } // Use a loop to ensure multiple calls in a single interval space out while (Date.now() - TerminalProcess._lastKillOrStart < Constants.KillSpawnThrottleInterval) { this._logService.trace('Throttling kill/spawn call'); diff --git a/src/vs/platform/theme/common/colors/editorColors.ts b/src/vs/platform/theme/common/colors/editorColors.ts index 567343b005552..a45e35a5c840b 100644 --- a/src/vs/platform/theme/common/colors/editorColors.ts +++ b/src/vs/platform/theme/common/colors/editorColors.ts @@ -134,6 +134,10 @@ export const editorSelectionHighlightBorder = registerColor('editor.selectionHig { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('editorSelectionHighlightBorder', "Border color for regions with the same content as the selection.")); +export const editorCompositionBorder = registerColor('editor.compositionBorder', + { light: '#000000', dark: '#ffffff', hcLight: '#000000', hcDark: '#ffffff' }, + nls.localize('editorCompositionBorder', "The border color for the composition.")); + // ----- editor find diff --git a/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts b/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts index 1386e87f2b54e..199813a3b8c7a 100644 --- a/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts +++ b/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts @@ -264,7 +264,7 @@ export class UtilityProcess extends Disposable { const env: { [key: string]: any } = configuration.env ? { ...configuration.env } : { ...deepClone(process.env) }; // Apply supported environment variables from config - env['VSCODE_AMD_ENTRYPOINT'] = configuration.entryPoint; + env['VSCODE_ESM_ENTRYPOINT'] = configuration.entryPoint; if (typeof configuration.parentLifecycleBound === 'number') { env['VSCODE_PARENT_PID'] = String(configuration.parentLifecycleBound); } diff --git a/src/vs/platform/window/electron-sandbox/window.ts b/src/vs/platform/window/electron-sandbox/window.ts index 1adaa55008133..233f3cdeb78a3 100644 --- a/src/vs/platform/window/electron-sandbox/window.ts +++ b/src/vs/platform/window/electron-sandbox/window.ts @@ -6,6 +6,7 @@ import { getZoomLevel, setZoomFactor, setZoomLevel } from '../../../base/browser/browser.js'; import { getActiveWindow, getWindows } from '../../../base/browser/dom.js'; import { mainWindow } from '../../../base/browser/window.js'; +import { ISandboxConfiguration } from '../../../base/parts/sandbox/common/sandboxTypes.js'; import { ISandboxGlobals, ipcRenderer, webFrame } from '../../../base/parts/sandbox/electron-sandbox/globals.js'; import { zoomLevelToZoomFactor } from '../common/window.js'; @@ -62,3 +63,26 @@ export function zoomIn(target: ApplyZoomTarget | Window): void { export function zoomOut(target: ApplyZoomTarget | Window): void { applyZoom(getZoomLevel(typeof target === 'number' ? getActiveWindow() : target) - 1, target); } + +//#region Bootstrap Window + +export interface ILoadOptions { + configureDeveloperSettings?: (config: T) => { + forceDisableShowDevtoolsOnError?: boolean; + forceEnableDeveloperKeybindings?: boolean; + disallowReloadKeybinding?: boolean; + removeDeveloperKeybindingsAfterLoad?: boolean; + }; + canModifyDOM?: (config: T) => void; + beforeImport?: (config: T) => void; +} + +export interface IBootstrapWindow { + load( + esModule: string, + resultCallback: (result: any, configuration: T) => Promise | undefined, + options: ILoadOptions + ): Promise; +} + +//#endregion diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index ae108b99c3c79..f0540656eedb4 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -43,7 +43,6 @@ import { IStateService } from '../../state/node/state.js'; import { IUserDataProfilesMainService } from '../../userDataProfile/electron-main/userDataProfile.js'; import { ILoggerMainService } from '../../log/electron-main/loggerService.js'; import { IInstantiationService } from '../../instantiation/common/instantiation.js'; -import { isESM } from '../../../base/common/amd.js'; export interface IWindowCreationOptions { readonly state: IWindowState; @@ -1036,7 +1035,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { this.readyState = ReadyState.NAVIGATING; // Load URL - this._win.loadURL(FileAccess.asBrowserUri(`vs/code/electron-sandbox/workbench/workbench${this.environmentMainService.isBuilt ? '' : '-dev'}.${isESM ? 'esm.' : ''}html`).toString(true)); + this._win.loadURL(FileAccess.asBrowserUri(`vs/code/electron-sandbox/workbench/workbench${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)); // Remember that we did load const wasLoaded = this.wasLoaded; diff --git a/src/vs/server/node/extensionHostConnection.ts b/src/vs/server/node/extensionHostConnection.ts index ab484be52a903..a3584893505f7 100644 --- a/src/vs/server/node/extensionHostConnection.ts +++ b/src/vs/server/node/extensionHostConnection.ts @@ -41,7 +41,7 @@ export async function buildUserEnvironment(startParamsEnv: { [key: string]: stri ...processEnv, ...userShellEnv, ...{ - VSCODE_AMD_ENTRYPOINT: 'vs/workbench/api/node/extensionHostProcess', + VSCODE_ESM_ENTRYPOINT: 'vs/workbench/api/node/extensionHostProcess', VSCODE_HANDLES_UNCAUGHT_ERRORS: 'true', VSCODE_NLS_CONFIG: JSON.stringify(nlsConfig) }, diff --git a/src/vs/server/node/remoteExtensionHostAgentServer.ts b/src/vs/server/node/remoteExtensionHostAgentServer.ts index c77fbfd373687..77b124f970008 100644 --- a/src/vs/server/node/remoteExtensionHostAgentServer.ts +++ b/src/vs/server/node/remoteExtensionHostAgentServer.ts @@ -9,7 +9,6 @@ import * as http from 'http'; import * as net from 'net'; import { performance } from 'perf_hooks'; import * as url from 'url'; -import { LoaderStats, isESM } from '../../base/common/amd.js'; import { VSBuffer } from '../../base/common/buffer.js'; import { CharCode } from '../../base/common/charCode.js'; import { isSigPipeError, onUnexpectedError, setUnexpectedErrorHandler } from '../../base/common/errors.js'; @@ -40,10 +39,8 @@ import { determineServerConnectionToken, requestHasValidConnectionToken as httpR import { IServerEnvironmentService, ServerParsedArgs } from './serverEnvironmentService.js'; import { setupServerServices, SocketServer } from './serverServices.js'; import { CacheControl, serveError, serveFile, WebClientServer } from './webClientServer.js'; -// ESM-uncomment-begin import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); -// ESM-uncomment-end const SHUTDOWN_TIMEOUT = 5 * 60 * 1000; @@ -785,7 +782,7 @@ export async function createServer(address: string | net.AddressInfo | null, arg serverBasePath = `/${serverBasePath}`; } - const hasWebClient = fs.existsSync(FileAccess.asFileUri(`vs/code/browser/workbench/workbench.${isESM ? 'esm.' : ''}html`).fsPath); + const hasWebClient = fs.existsSync(FileAccess.asFileUri(`vs/code/browser/workbench/workbench.html`).fsPath); if (hasWebClient && address && typeof address !== 'string') { // ships the web ui! @@ -851,16 +848,7 @@ export async function createServer(address: string | net.AddressInfo | null, arg }); if (args['print-startup-performance']) { - const stats = LoaderStats.get(); let output = ''; - output += '\n\n### Load AMD-module\n'; - output += LoaderStats.toMarkdownTable(['Module', 'Duration'], stats.amdLoad); - output += '\n\n### Load commonjs-module\n'; - output += LoaderStats.toMarkdownTable(['Module', 'Duration'], stats.nodeRequire); - output += '\n\n### Invoke AMD-module factory\n'; - output += LoaderStats.toMarkdownTable(['Module', 'Duration'], stats.amdInvoke); - output += '\n\n### Invoke commonjs-module\n'; - output += LoaderStats.toMarkdownTable(['Module', 'Duration'], stats.nodeEval); output += `Start-up time: ${vscodeServerListenTime - vscodeServerStartTime}\n`; output += `Code loading time: ${vscodeServerCodeLoadedTime - vscodeServerStartTime}\n`; output += `Initialized time: ${currentTime - vscodeServerStartTime}\n`; diff --git a/src/vs/server/node/webClientServer.ts b/src/vs/server/node/webClientServer.ts index 6ef3eac5f0281..7c6430e238067 100644 --- a/src/vs/server/node/webClientServer.ts +++ b/src/vs/server/node/webClientServer.ts @@ -28,7 +28,6 @@ import { IProductConfiguration } from '../../base/common/product.js'; import { isString } from '../../base/common/types.js'; import { CharCode } from '../../base/common/charCode.js'; import { IExtensionManifest } from '../../platform/extensions/common/extensions.js'; -import { isESM } from '../../base/common/amd.js'; import { ICSSDevelopmentService } from '../../platform/cssDev/node/cssDevService.js'; const textMimeType: { [ext: string]: string | undefined } = { @@ -300,7 +299,7 @@ export class WebClientServer { const resolveWorkspaceURI = (defaultLocation?: string) => defaultLocation && URI.file(path.resolve(defaultLocation)).with({ scheme: Schemas.vscodeRemote, authority: remoteAuthority }); - const filePath = FileAccess.asFileUri(`vs/code/browser/workbench/workbench${this._environmentService.isBuilt ? '' : '-dev'}.${isESM ? 'esm.' : ''}html`).fsPath; + const filePath = FileAccess.asFileUri(`vs/code/browser/workbench/workbench${this._environmentService.isBuilt ? '' : '-dev'}.html`).fsPath; const authSessionInfo = !this._environmentService.isBuilt && this._environmentService.args['github-auth'] ? { id: generateUuid(), providerId: 'github', @@ -387,15 +386,13 @@ export class WebClientServer { return void res.end('Not found'); } - const webWorkerExtensionHostIframeScriptSHA = isESM ? 'sha256-2Q+j4hfT09+1+imS46J2YlkCtHWQt0/BE79PXjJ0ZJ8=' : 'sha256-V28GQnL3aYxbwgpV3yW1oJ+VKKe/PBSzWntNyH8zVXA='; + const webWorkerExtensionHostIframeScriptSHA = 'sha256-2Q+j4hfT09+1+imS46J2YlkCtHWQt0/BE79PXjJ0ZJ8='; const cspDirectives = [ 'default-src \'self\';', 'img-src \'self\' https: data: blob:;', 'media-src \'self\';', - isESM ? - `script-src 'self' 'unsafe-eval' ${WORKBENCH_NLS_BASE_URL ?? ''} blob: 'nonce-1nline-m4p' ${this._getScriptCspHashes(data).join(' ')} '${webWorkerExtensionHostIframeScriptSHA}' 'sha256-/r7rqQ+yrxt57sxLuQ6AMYcy/lUpvAIzHjIJt/OeLWU=' ${useTestResolver ? '' : `http://${remoteAuthority}`};` : // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html - `script-src 'self' 'unsafe-eval' ${WORKBENCH_NLS_BASE_URL ?? ''} ${this._getScriptCspHashes(data).join(' ')} '${webWorkerExtensionHostIframeScriptSHA}' ${useTestResolver ? '' : `http://${remoteAuthority}`};`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html + `script-src 'self' 'unsafe-eval' ${WORKBENCH_NLS_BASE_URL ?? ''} blob: 'nonce-1nline-m4p' ${this._getScriptCspHashes(data).join(' ')} '${webWorkerExtensionHostIframeScriptSHA}' 'sha256-/r7rqQ+yrxt57sxLuQ6AMYcy/lUpvAIzHjIJt/OeLWU=' ${useTestResolver ? '' : `http://${remoteAuthority}`};`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html 'child-src \'self\';', `frame-src 'self' https://*.vscode-cdn.net data:;`, 'worker-src \'self\' data: blob:;', diff --git a/src/vs/workbench/api/browser/mainThreadSCM.ts b/src/vs/workbench/api/browser/mainThreadSCM.ts index 3a90525f8eb0a..fbb4340c5ec62 100644 --- a/src/vs/workbench/api/browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/browser/mainThreadSCM.ts @@ -271,7 +271,6 @@ class MainThreadSCMProvider implements ISCMProvider, QuickDiffProvider { get contextValue(): string { return this._providerId; } get acceptInputCommand(): Command | undefined { return this.features.acceptInputCommand; } - get actionButton(): ISCMActionButtonDescriptor | undefined { return this.features.actionButton ?? undefined; } private readonly _count = observableValue(this, undefined); get count() { return this._count; } @@ -285,8 +284,8 @@ class MainThreadSCMProvider implements ISCMProvider, QuickDiffProvider { private readonly _commitTemplate = observableValue(this, ''); get commitTemplate() { return this._commitTemplate; } - private readonly _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private readonly _actionButton = observableValue(this, undefined); + get actionButton(): IObservable { return this._actionButton; } private _quickDiff: IDisposable | undefined; public readonly isSCM: boolean = true; @@ -317,12 +316,15 @@ class MainThreadSCMProvider implements ISCMProvider, QuickDiffProvider { $updateSourceControl(features: SCMProviderFeatures): void { this.features = { ...this.features, ...features }; - this._onDidChange.fire(); if (typeof features.commitTemplate !== 'undefined') { this._commitTemplate.set(features.commitTemplate, undefined); } + if (typeof features.actionButton !== 'undefined') { + this._actionButton.set(features.actionButton, undefined); + } + if (typeof features.count !== 'undefined') { this._count.set(features.count, undefined); } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 2e335cbaa5da6..8c04da5bb7c44 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1454,7 +1454,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, registerChatParticipantDetectionProvider(provider: vscode.ChatParticipantDetectionProvider) { checkProposedApiEnabled(extension, 'chatParticipantAdditions'); - return extHostChatAgents2.registerChatParticipantDetectionProvider(provider); + return extHostChatAgents2.registerChatParticipantDetectionProvider(extension, provider); }, }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 4900f545fb406..26b584ef5f703 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1534,14 +1534,13 @@ export interface SCMProviderFeatures { count?: number; commitTemplate?: string; acceptInputCommand?: languages.Command; - actionButton?: SCMActionButtonDto | null; + actionButton?: SCMActionButtonDto; statusBarCommands?: ICommandDto[]; } export interface SCMActionButtonDto { - command: ICommandDto; + command: ICommandDto & { shortTitle?: string }; secondaryCommands?: ICommandDto[][]; - description?: string; enabled: boolean; } diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index cc1ecb1291290..c31f91957d7fb 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -285,7 +285,7 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS private readonly _proxy: MainThreadChatAgentsShape2; private static _participantDetectionProviderIdPool = 0; - private readonly _participantDetectionProviders = new Map(); + private readonly _participantDetectionProviders = new Map(); private readonly _sessionDisposables: DisposableMap = this._register(new DisposableMap()); private readonly _completionDisposables: DisposableMap = this._register(new DisposableMap()); @@ -323,9 +323,9 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS return agent.apiAgent; } - registerChatParticipantDetectionProvider(provider: vscode.ChatParticipantDetectionProvider): vscode.Disposable { + registerChatParticipantDetectionProvider(extension: IExtensionDescription, provider: vscode.ChatParticipantDetectionProvider): vscode.Disposable { const handle = ExtHostChatAgents2._participantDetectionProviderIdPool++; - this._participantDetectionProviders.set(handle, provider); + this._participantDetectionProviders.set(handle, new ExtHostParticipantDetector(extension, provider)); this._proxy.$registerChatParticipantDetectionProvider(handle); return toDisposable(() => { this._participantDetectionProviders.delete(handle); @@ -336,13 +336,18 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS async $detectChatParticipant(handle: number, requestDto: Dto, context: { history: IChatAgentHistoryEntryDto[] }, options: { location: ChatAgentLocation; participants?: vscode.ChatParticipantMetadata[] }, token: CancellationToken): Promise { const { request, location, history } = await this._createRequest(requestDto, context); - const provider = this._participantDetectionProviders.get(handle); - if (!provider) { + const detector = this._participantDetectionProviders.get(handle); + if (!detector) { return undefined; } - return provider.provideParticipantDetection( - typeConvert.ChatAgentRequest.to(request, location), + const extRequest = typeConvert.ChatAgentRequest.to(request, location); + if (request.userSelectedModelId && isProposedApiEnabled(detector.extension, 'chatParticipantAdditions')) { + extRequest.userSelectedModel = await this._languageModels.getLanguageModelByIdentifier(detector.extension, request.userSelectedModelId); + } + + return detector.provider.provideParticipantDetection( + extRequest, { history }, { participants: options.participants, location: typeConvert.ChatLocation.to(options.location) }, token @@ -588,6 +593,13 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS } } +class ExtHostParticipantDetector { + constructor( + public readonly extension: IExtensionDescription, + public readonly provider: vscode.ChatParticipantDetectionProvider, + ) { } +} + class ExtHostChatAgent { private _followupProvider: vscode.ChatFollowupProvider | undefined; diff --git a/src/vs/workbench/api/common/extHostCodeMapper.ts b/src/vs/workbench/api/common/extHostCodeMapper.ts index 055d52b3d4b49..0f6b9d1292238 100644 --- a/src/vs/workbench/api/common/extHostCodeMapper.ts +++ b/src/vs/workbench/api/common/extHostCodeMapper.ts @@ -8,7 +8,7 @@ import { CancellationToken } from '../../../base/common/cancellation.js'; import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js'; import { ICodeMapperResult } from '../../contrib/chat/common/chatCodeMapperService.js'; import * as extHostProtocol from './extHost.protocol.js'; -import { TextEdit } from './extHostTypeConverters.js'; +import { ChatAgentResult, DocumentContextItem, TextEdit } from './extHostTypeConverters.js'; import { URI } from '../../../base/common/uri.js'; export class ExtHostCodeMapper implements extHostProtocol.ExtHostCodeMapperShape { @@ -45,10 +45,25 @@ export class ExtHostCodeMapper implements extHostProtocol.ExtHostCodeMapperShape codeBlocks: internalRequest.codeBlocks.map(block => { return { code: block.code, - resource: URI.revive(block.resource) + resource: URI.revive(block.resource), + markdownBeforeBlock: block.markdownBeforeBlock }; }), - conversation: internalRequest.conversation + conversation: internalRequest.conversation.map(item => { + if (item.type === 'request') { + return { + type: 'request', + message: item.message + } satisfies vscode.ConversationRequest; + } else { + return { + type: 'response', + message: item.message, + result: item.result ? ChatAgentResult.to(item.result) : undefined, + references: item.references?.map(DocumentContextItem.to) + } satisfies vscode.ConversationResponse; + } + }) }; const result = await provider.provideMappedEdits(request, stream, token); diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index c7aeef7a164c8..6b8ba4c15956d 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -19,19 +19,17 @@ import { VSBuffer } from '../../../base/common/buffer.js'; import { isString } from '../../../base/common/types.js'; import { FileSystemProviderErrorCode, toFileSystemProviderErrorCode } from '../../../platform/files/common/files.js'; import { Emitter } from '../../../base/common/event.js'; -import { DisposableStore } from '../../../base/common/lifecycle.js'; +import { DisposableStore, toDisposable } from '../../../base/common/lifecycle.js'; class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOutputChannel { private offset: number = 0; - private _disposed: boolean = false; - get disposed(): boolean { return this._disposed; } - public visible: boolean = false; constructor( - readonly id: string, readonly name: string, + readonly id: string, + readonly name: string, protected readonly logger: ILogger, protected readonly proxy: MainThreadOutputServiceShape, readonly extension: IExtensionDescription, @@ -39,6 +37,7 @@ class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOu super(); this.setLevel(logger.getLevel()); this._register(logger.onDidChangeLogLevel(level => this.setLevel(level))); + this._register(toDisposable(() => this.proxy.$dispose(this.id))); } get logLevel(): LogLevel { @@ -86,15 +85,6 @@ class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOu } } - override dispose(): void { - super.dispose(); - - if (!this._disposed) { - this.proxy.$dispose(this.id); - this._disposed = true; - } - } - } class ExtHostLogOutputChannel extends ExtHostOutputChannel { @@ -153,31 +143,39 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { if (logLevelValue) { logLevel = parseLogLevel(logLevelValue); } - const extHostOutputChannel = log ? this.doCreateLogOutputChannel(name, logLevel, extension) : this.doCreateOutputChannel(name, languageId, extension); + const channelDisposables = new DisposableStore(); + const extHostOutputChannel = log + ? this.doCreateLogOutputChannel(name, logLevel, extension, channelDisposables) + : this.doCreateOutputChannel(name, languageId, extension, channelDisposables); extHostOutputChannel.then(channel => { this.channels.set(channel.id, channel); channel.visible = channel.id === this.visibleChannelId; + channelDisposables.add(toDisposable(() => this.channels.delete(channel.id))); }); - return log ? this.createExtHostLogOutputChannel(name, logLevel ?? this.logService.getLevel(), >extHostOutputChannel) : this.createExtHostOutputChannel(name, >extHostOutputChannel); + return log + ? this.createExtHostLogOutputChannel(name, logLevel ?? this.logService.getLevel(), >extHostOutputChannel, channelDisposables) + : this.createExtHostOutputChannel(name, >extHostOutputChannel, channelDisposables); } - private async doCreateOutputChannel(name: string, languageId: string | undefined, extension: IExtensionDescription): Promise { + private async doCreateOutputChannel(name: string, languageId: string | undefined, extension: IExtensionDescription, channelDisposables: DisposableStore): Promise { if (!this.outputDirectoryPromise) { this.outputDirectoryPromise = this.extHostFileSystem.value.createDirectory(this.outputsLocation).then(() => this.outputsLocation); } const outputDir = await this.outputDirectoryPromise; const file = this.extHostFileSystemInfo.extUri.joinPath(outputDir, `${this.namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`); - const logger = this.loggerService.createLogger(file, { logLevel: 'always', donotRotate: true, donotUseFormatters: true, hidden: true }); + const logger = channelDisposables.add(this.loggerService.createLogger(file, { logLevel: 'always', donotRotate: true, donotUseFormatters: true, hidden: true })); const id = await this.proxy.$register(name, file, languageId, extension.identifier.value); + channelDisposables.add(toDisposable(() => this.loggerService.deregisterLogger(file))); return new ExtHostOutputChannel(id, name, logger, this.proxy, extension); } - private async doCreateLogOutputChannel(name: string, logLevel: LogLevel | undefined, extension: IExtensionDescription): Promise { + private async doCreateLogOutputChannel(name: string, logLevel: LogLevel | undefined, extension: IExtensionDescription, channelDisposables: DisposableStore): Promise { const extensionLogDir = await this.createExtensionLogDirectory(extension); const fileName = name.replace(/[\\/:\*\?"<>\|]/g, ''); const file = this.extHostFileSystemInfo.extUri.joinPath(extensionLogDir, `${fileName}.log`); const id = `${extension.identifier.value}.${fileName}`; - const logger = this.loggerService.createLogger(file, { id, name, logLevel, extensionId: extension.identifier.value }); + const logger = channelDisposables.add(this.loggerService.createLogger(file, { id, name, logLevel, extensionId: extension.identifier.value })); + channelDisposables.add(toDisposable(() => this.loggerService.deregisterLogger(file))); return new ExtHostLogOutputChannel(id, name, logger, this.proxy, extension); } @@ -199,13 +197,13 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { return extensionLogDirectoryPromise; } - private createExtHostOutputChannel(name: string, channelPromise: Promise): vscode.OutputChannel { - let disposed = false; + private createExtHostOutputChannel(name: string, channelPromise: Promise, channelDisposables: DisposableStore): vscode.OutputChannel { const validate = () => { - if (disposed) { + if (channelDisposables.isDisposed) { throw new Error('Channel has been closed'); } }; + channelPromise.then(channel => channelDisposables.add(channel)); return { get name(): string { return name; }, append(value: string): void { @@ -233,33 +231,30 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { channelPromise.then(channel => channel.hide()); }, dispose(): void { - disposed = true; - channelPromise.then(channel => channel.dispose()); + channelDisposables.dispose(); } }; } - private createExtHostLogOutputChannel(name: string, logLevel: LogLevel, channelPromise: Promise): vscode.LogOutputChannel { - const disposables = new DisposableStore(); + private createExtHostLogOutputChannel(name: string, logLevel: LogLevel, channelPromise: Promise, channelDisposables: DisposableStore): vscode.LogOutputChannel { const validate = () => { - if (disposables.isDisposed) { + if (channelDisposables.isDisposed) { throw new Error('Channel has been closed'); } }; - const onDidChangeLogLevel = disposables.add(new Emitter()); + const onDidChangeLogLevel = channelDisposables.add(new Emitter()); function setLogLevel(newLogLevel: LogLevel): void { logLevel = newLogLevel; onDidChangeLogLevel.fire(newLogLevel); } channelPromise.then(channel => { - disposables.add(channel); if (channel.logLevel !== logLevel) { setLogLevel(channel.logLevel); } - disposables.add(channel.onDidChangeLogLevel(e => setLogLevel(e))); + channelDisposables.add(channel.onDidChangeLogLevel(e => setLogLevel(e))); }); return { - ...this.createExtHostOutputChannel(name, channelPromise), + ...this.createExtHostOutputChannel(name, channelPromise, channelDisposables), get logLevel() { return logLevel; }, onDidChangeLogLevel: onDidChangeLogLevel.event, trace(value: string, ...args: any[]): void { @@ -281,9 +276,6 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { error(value: Error | string, ...args: any[]): void { validate(); channelPromise.then(channel => channel.error(value, ...args)); - }, - dispose(): void { - disposables.dispose(); } }; } diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 53ddbe4d9dbbb..85e5cba53945f 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -11,7 +11,7 @@ import { debounce } from '../../../base/common/decorators.js'; import { DisposableStore, IDisposable, MutableDisposable } from '../../../base/common/lifecycle.js'; import { asPromise } from '../../../base/common/async.js'; import { ExtHostCommands } from './extHostCommands.js'; -import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, ICommandDto, MainThreadTelemetryShape, SCMGroupFeatures, SCMHistoryItemDto, SCMHistoryItemChangeDto, SCMHistoryItemRefDto } from './extHost.protocol.js'; +import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, ICommandDto, MainThreadTelemetryShape, SCMGroupFeatures, SCMHistoryItemDto, SCMHistoryItemChangeDto, SCMHistoryItemRefDto, SCMActionButtonDto } from './extHost.protocol.js'; import { sortedDiff, equals } from '../../../base/common/arrays.js'; import { comparePaths } from '../../../base/common/comparers.js'; import type * as vscode from 'vscode'; @@ -27,6 +27,7 @@ import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/ex import { ExtHostDocuments } from './extHostDocuments.js'; import { Schemas } from '../../../base/common/network.js'; import { isLinux } from '../../../base/common/platform.js'; +import { structuralEquals } from '../../../base/common/equals.js'; type ProviderHandle = number; type GroupHandle = number; @@ -654,22 +655,33 @@ class ExtHostSourceControl implements vscode.SourceControl { checkProposedApiEnabled(this._extension, 'scmActionButton'); return this._actionButton; } + set actionButton(actionButton: vscode.SourceControlActionButton | undefined) { checkProposedApiEnabled(this._extension, 'scmActionButton'); - this._actionButtonDisposables.value = new DisposableStore(); + + // We have to do this check before converting the command to it's internal + // representation since that would always create a command with a unique + // identifier + if (structuralEquals(this._actionButton, actionButton)) { + return; + } this._actionButton = actionButton; + this._actionButtonDisposables.value = new DisposableStore(); - const internal = actionButton !== undefined ? + const actionButtonDto = actionButton !== undefined ? { - command: this._commands.converter.toInternal(actionButton.command, this._actionButtonDisposables.value), + command: { + ...this._commands.converter.toInternal(actionButton.command, this._actionButtonDisposables.value), + shortTitle: actionButton.command.shortTitle + }, secondaryCommands: actionButton.secondaryCommands?.map(commandGroup => { return commandGroup.map(command => this._commands.converter.toInternal(command, this._actionButtonDisposables.value!)); }), - description: actionButton.description, enabled: actionButton.enabled - } : undefined; - this.#proxy.$updateSourceControl(this.handle, { actionButton: internal ?? null }); + } satisfies SCMActionButtonDto : undefined; + + this.#proxy.$updateSourceControl(this.handle, { actionButton: actionButtonDto }); } @@ -995,26 +1007,54 @@ export class ExtHostSCM implements ExtHostSCMShape { } async $resolveHistoryItemRefsCommonAncestor(sourceControlHandle: number, historyItemRefs: string[], token: CancellationToken): Promise { - const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; - return await historyProvider?.resolveHistoryItemRefsCommonAncestor(historyItemRefs, token) ?? undefined; + try { + const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; + const ancestor = await historyProvider?.resolveHistoryItemRefsCommonAncestor(historyItemRefs, token); + + return ancestor ?? undefined; + } + catch (err) { + this.logService.error('ExtHostSCM#$resolveHistoryItemRefsCommonAncestor', err); + return undefined; + } } async $provideHistoryItemRefs(sourceControlHandle: number, historyItemRefs: string[] | undefined, token: CancellationToken): Promise { - const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; - const refs = await historyProvider?.provideHistoryItemRefs(historyItemRefs, token); + try { + const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; + const refs = await historyProvider?.provideHistoryItemRefs(historyItemRefs, token); - return refs?.map(ref => ({ ...ref, icon: getHistoryItemIconDto(ref.icon) })) ?? undefined; + return refs?.map(ref => ({ ...ref, icon: getHistoryItemIconDto(ref.icon) })) ?? undefined; + } + catch (err) { + this.logService.error('ExtHostSCM#$provideHistoryItemRefs', err); + return undefined; + } } async $provideHistoryItems(sourceControlHandle: number, options: any, token: CancellationToken): Promise { - const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; - const historyItems = await historyProvider?.provideHistoryItems(options, token); + try { + const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; + const historyItems = await historyProvider?.provideHistoryItems(options, token); - return historyItems?.map(item => toSCMHistoryItemDto(item)) ?? undefined; + return historyItems?.map(item => toSCMHistoryItemDto(item)) ?? undefined; + } + catch (err) { + this.logService.error('ExtHostSCM#$provideHistoryItems', err); + return undefined; + } } async $provideHistoryItemChanges(sourceControlHandle: number, historyItemId: string, historyItemParentId: string | undefined, token: CancellationToken): Promise { - const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; - return await historyProvider?.provideHistoryItemChanges(historyItemId, historyItemParentId, token) ?? undefined; + try { + const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; + const changes = await historyProvider?.provideHistoryItemChanges(historyItemId, historyItemParentId, token); + + return changes ?? undefined; + } + catch (err) { + this.logService.error('ExtHostSCM#$provideHistoryItemChanges', err); + return undefined; + } } } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index f893d7e779638..14f182efbe17b 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1629,7 +1629,7 @@ export namespace MappedEditsContext { ); } - export function from(extContext: vscode.MappedEditsContext): languages.MappedEditsContext { + export function from(extContext: vscode.MappedEditsContext): Dto { return { documents: extContext.documents.map((subArray) => subArray.map(DocumentContextItem.from) @@ -1643,6 +1643,7 @@ export namespace MappedEditsContext { { type: 'response', message: item.message, + result: item.result ? ChatAgentResult.from(item.result) : undefined, references: item.references?.map(DocumentContextItem.from) } )) @@ -1663,13 +1664,21 @@ export namespace DocumentContextItem { ); } - export function from(item: vscode.DocumentContextItem): languages.DocumentContextItem { + export function from(item: vscode.DocumentContextItem): Dto { return { - uri: URI.from(item.uri), + uri: item.uri, version: item.version, ranges: item.ranges.map(r => Range.from(r)), }; } + + export function to(item: Dto): vscode.DocumentContextItem { + return { + uri: URI.revive(item.uri), + version: item.version, + ranges: item.ranges.map(r => Range.to(r)), + }; + } } export namespace NotebookRange { @@ -2759,6 +2768,7 @@ export namespace ChatLocation { case ChatAgentLocation.Terminal: return types.ChatLocation.Terminal; case ChatAgentLocation.Panel: return types.ChatLocation.Panel; case ChatAgentLocation.Editor: return types.ChatLocation.Editor; + case ChatAgentLocation.EditingSession: return types.ChatLocation.EditingSession; } } @@ -2768,6 +2778,7 @@ export namespace ChatLocation { case types.ChatLocation.Terminal: return ChatAgentLocation.Terminal; case types.ChatLocation.Panel: return ChatAgentLocation.Panel; case types.ChatLocation.Editor: return ChatAgentLocation.Editor; + case types.ChatLocation.EditingSession: return ChatAgentLocation.EditingSession; } } } @@ -2829,6 +2840,13 @@ export namespace ChatAgentResult { nextQuestion: result.nextQuestion, }; } + export function from(result: vscode.ChatResult): Dto { + return { + errorDetails: result.errorDetails, + metadata: result.metadata, + nextQuestion: result.nextQuestion, + }; + } } export namespace ChatAgentUserActionEvent { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index ada4e5e515603..d7c85bd8b3733 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4538,6 +4538,7 @@ export enum ChatLocation { Terminal = 2, Notebook = 3, Editor = 4, + EditingSession = 5, } export enum ChatResponseReferencePartStatusKind { diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 51e767f1fdc10..7fae836bf4352 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -18,10 +18,8 @@ import { CLIServer } from './extHostCLIServer.js'; import { realpathSync } from '../../../base/node/extpath.js'; import { ExtHostConsoleForwarder } from './extHostConsoleForwarder.js'; import { ExtHostDiskFileSystemProvider } from './extHostDiskFileSystemProvider.js'; -// ESM-uncomment-begin import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); -// ESM-uncomment-end class NodeModuleRequireInterceptor extends RequireInterceptor { @@ -46,7 +44,6 @@ class NodeModuleRequireInterceptor extends RequireInterceptor { return originalLookup.call(this, applyAlternatives(request), parent); }; - // ESM-uncomment-begin const originalResolveFilename = node_module._resolveFilename; node_module._resolveFilename = function resolveFilename(request: string, parent: unknown, isMain: boolean, options?: { paths?: string[] }) { if (request === 'vsda' && Array.isArray(options?.paths) && options.paths.length === 0) { @@ -58,7 +55,6 @@ class NodeModuleRequireInterceptor extends RequireInterceptor { } return originalResolveFilename.call(this, request, parent, isMain, options); }; - // ESM-uncomment-end const applyAlternatives = (request: string) => { for (const alternativeModuleName of that._alternatives) { @@ -127,7 +123,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { if (extensionId) { performance.mark(`code/extHost/willLoadExtensionCode/${extensionId}`); } - r = (require.__$__nodeRequire ?? require /* TODO@esm drop the first */)(module.fsPath); + r = (require)(module.fsPath); } finally { if (extensionId) { performance.mark(`code/extHost/didLoadExtensionCode/${extensionId}`); diff --git a/src/vs/workbench/api/node/extensionHostProcess.ts b/src/vs/workbench/api/node/extensionHostProcess.ts index 694559385c436..feaece95534e4 100644 --- a/src/vs/workbench/api/node/extensionHostProcess.ts +++ b/src/vs/workbench/api/node/extensionHostProcess.ts @@ -28,10 +28,8 @@ import { ExtensionHostExitCode, IExtHostReadyMessage, IExtHostReduceGraceTimeMes import { IDisposable } from '../../../base/common/lifecycle.js'; import '../common/extHost.common.services.js'; import './extHost.node.services.js'; -// ESM-uncomment-begin import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); -// ESM-uncomment-end interface ParsedExtHostArgs { transformURIs?: boolean; diff --git a/src/vs/workbench/api/node/proxyResolver.ts b/src/vs/workbench/api/node/proxyResolver.ts index 3f6253c78ecf4..e23039e6c6b7e 100644 --- a/src/vs/workbench/api/node/proxyResolver.ts +++ b/src/vs/workbench/api/node/proxyResolver.ts @@ -3,13 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -// ESM-comment-begin -// import * as http from 'http'; -// import * as https from 'https'; -// import * as tls from 'tls'; -// import * as net from 'net'; -// ESM-comment-end - import { IExtHostWorkspaceProvider } from '../common/extHostWorkspace.js'; import { ExtHostConfigProvider } from '../common/extHostConfiguration.js'; import { MainThreadTelemetryShape } from '../common/extHost.protocol.js'; @@ -21,15 +14,13 @@ import { IExtensionDescription } from '../../../platform/extensions/common/exten import { LogLevel, createHttpPatch, createProxyResolver, createTlsPatch, ProxySupportSetting, ProxyAgentParams, createNetPatch, loadSystemCertificates } from '@vscode/proxy-agent'; import { AuthInfo } from '../../../platform/request/common/request.js'; import { DisposableStore } from '../../../base/common/lifecycle.js'; - -// ESM-uncomment-begin import { createRequire } from 'node:module'; + const require = createRequire(import.meta.url); const http = require('http'); const https = require('https'); const tls = require('tls'); const net = require('net'); -// ESM-uncomment-end const systemCertificatesV2Default = false; const useElectronFetchDefault = false; diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 5e83a9458bdf7..11577775c8e39 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -267,6 +267,10 @@ export class CompositeBar extends Widget implements ICompositeBar { return this.model.pinnedItems; } + getPinnedCompositeIds(): string[] { + return this.getPinnedComposites().map(c => c.id); + } + getVisibleComposites(): ICompositeBarItem[] { return this.model.visibleItems; } @@ -651,19 +655,22 @@ export class CompositeBar extends Widget implements ICompositeBar { getContextMenuActions(e?: MouseEvent | GestureEvent): IAction[] { const actions: IAction[] = this.model.visibleItems - .map(({ id, name, activityAction }) => (toAction({ - id, - label: this.getAction(id).label || name || id, - checked: this.isPinned(id), - enabled: activityAction.enabled, - run: () => { - if (this.isPinned(id)) { - this.unpin(id); - } else { - this.pin(id, true); + .map(({ id, name, activityAction }) => { + const isPinned = this.isPinned(id); + return toAction({ + id, + label: this.getAction(id).label || name || id, + checked: isPinned, + enabled: activityAction.enabled && (!isPinned || this.getPinnedCompositeIds().length > 1), + run: () => { + if (this.isPinned(id)) { + this.unpin(id); + } else { + this.pin(id, true); + } } - } - }))); + }); + }); this.options.fillExtraContextMenuActions(actions, e); diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index 15f6b06331c8e..89876b6dffc61 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -45,6 +45,11 @@ export interface ICompositeBar { */ isPinned(compositeId: string): boolean; + /** + * Get pinned composite ids in the composite bar. + */ + getPinnedCompositeIds(): string[]; + /** * Returns if badges are enabled for that specified composite. * @param compositeId The id of the composite to check @@ -689,8 +694,10 @@ export class CompositeActionViewItem extends CompositeBarActionViewItem { if (isPinned) { this.toggleCompositePinnedAction.label = localize('hide', "Hide '{0}'", this.compositeBarActionItem.name); this.toggleCompositePinnedAction.checked = false; + this.toggleCompositePinnedAction.enabled = this.compositeBar.getPinnedCompositeIds().length > 1; } else { this.toggleCompositePinnedAction.label = localize('keep', "Keep '{0}'", this.compositeBarActionItem.name); + this.toggleCompositePinnedAction.enabled = true; } const isBadgeEnabled = this.compositeBar.areBadgesEnabled(this.compositeBarActionItem.id); diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index f081430e49fe3..b40c9fa73a975 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import './style.js'; -import { localize } from '../../nls.js'; import { runWhenWindowIdle } from '../../base/browser/dom.js'; import { Event, Emitter, setGlobalLeakWarningThreshold } from '../../base/common/event.js'; import { RunOnceScheduler, timeout } from '../../base/common/async.js'; @@ -50,7 +49,6 @@ import { AccessibilityProgressSignalScheduler } from '../../platform/accessibili import { setProgressAcccessibilitySignalScheduler } from '../../base/browser/ui/progressbar/progressAccessibilitySignal.js'; import { AccessibleViewRegistry } from '../../platform/accessibility/browser/accessibleViewRegistry.js'; import { NotificationAccessibleView } from './parts/notifications/notificationAccessibleView.js'; -import { isESM } from '../../base/common/amd.js'; export interface IWorkbenchOptions { @@ -98,31 +96,6 @@ export class Workbench extends Layout { // Install handler for unexpected errors setUnexpectedErrorHandler(error => this.handleUnexpectedError(error, logService)); - - // Inform user about loading issues from the loader - if (!isESM && typeof mainWindow.require?.config === 'function') { - interface AnnotatedLoadingError extends Error { - phase: 'loading'; - moduleId: string; - neededBy: string[]; - } - interface AnnotatedFactoryError extends Error { - phase: 'factory'; - moduleId: string; - } - interface AnnotatedValidationError extends Error { - phase: 'configuration'; - } - type AnnotatedError = AnnotatedLoadingError | AnnotatedFactoryError | AnnotatedValidationError; - mainWindow.require.config({ - onError: (err: AnnotatedError) => { - if (err.phase === 'loading') { - onUnexpectedError(new Error(localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err)))); - } - console.error(err); - } - }); - } } private previousUnexpectedError: { message: string | undefined; time: number } = { message: undefined, time: 0 }; diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts index 618d2b5a97912..c9c0311cc8d95 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts @@ -14,14 +14,17 @@ import { KeybindingWeight } from '../../../../../platform/keybinding/common/keyb import { ActiveEditorContext } from '../../../../common/contextkeys.js'; import { CHAT_CATEGORY, isChatViewTitleActionContext } from './chatActions.js'; import { clearChatEditor } from './chatClear.js'; -import { CHAT_VIEW_ID, IChatWidgetService } from '../chat.js'; +import { CHAT_VIEW_ID, EDITS_VIEW_ID, IChatWidgetService } from '../chat.js'; import { ChatEditorInput } from '../chatEditorInput.js'; import { ChatViewPane } from '../chatViewPane.js'; -import { CONTEXT_IN_CHAT_SESSION, CONTEXT_CHAT_ENABLED } from '../../common/chatContextKeys.js'; +import { CONTEXT_IN_CHAT_SESSION, CONTEXT_CHAT_ENABLED, CONTEXT_CHAT_EDITING_PARTICIPANT_REGISTERED } from '../../common/chatContextKeys.js'; import { IViewsService } from '../../../../services/views/common/viewsService.js'; +import { ChatAgentLocation } from '../../common/chatAgents.js'; export const ACTION_ID_NEW_CHAT = `workbench.action.chat.newChat`; +export const ACTION_ID_NEW_EDIT_SESSION = `workbench.action.chat.newEditSession`; + export function registerNewChatActions() { registerAction2(class NewChatEditorAction extends Action2 { constructor() { @@ -100,6 +103,54 @@ export function registerNewChatActions() { } } }); + + registerAction2(class GlobalClearEditsAction extends Action2 { + constructor() { + super({ + id: ACTION_ID_NEW_EDIT_SESSION, + title: localize2('chat.newEdits.label', "New Edit Session"), + category: CHAT_CATEGORY, + icon: Codicon.plus, + precondition: ContextKeyExpr.and(CONTEXT_CHAT_ENABLED, CONTEXT_CHAT_EDITING_PARTICIPANT_REGISTERED), + f1: true, + menu: [{ + id: MenuId.ChatContext, + group: 'z_clear' + }, + { + id: MenuId.ViewTitle, + when: ContextKeyExpr.equals('view', EDITS_VIEW_ID), + group: 'navigation', + order: -1 + }] + }); + } + + async run(accessor: ServicesAccessor, ...args: any[]) { + const context = args[0]; + const accessibilitySignalService = accessor.get(IAccessibilitySignalService); + if (isChatViewTitleActionContext(context)) { + // Is running in the Chat view title + announceChatCleared(accessibilitySignalService); + context.chatView.widget.clear(); + context.chatView.widget.focusInput(); + } else { + // Is running from f1 or keybinding + const widgetService = accessor.get(IChatWidgetService); + const viewsService = accessor.get(IViewsService); + + let widget = widgetService.lastFocusedWidget; + if (!widget || widget.location !== ChatAgentLocation.EditingSession) { + const chatView = await viewsService.openView(EDITS_VIEW_ID) as ChatViewPane; + widget = chatView.widget; + } + + announceChatCleared(accessibilitySignalService); + widget.clear(); + widget.focusInput(); + } + } + }); } function announceChatCleared(accessibilitySignalService: IAccessibilitySignalService): void { diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index c0870c8811057..3425dad368f04 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -3,15 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationTokenSource } from '../../../../../base/common/cancellation.js'; import { Codicon } from '../../../../../base/common/codicons.js'; import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js'; -import { URI } from '../../../../../base/common/uri.js'; import { ICodeEditor } from '../../../../../editor/browser/editorBrowser.js'; import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js'; import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; import { EditorContextKeys } from '../../../../../editor/common/editorContextKeys.js'; -import { TextEdit } from '../../../../../editor/common/languages.js'; import { CopyAction } from '../../../../../editor/contrib/clipboard/browser/clipboard.js'; import { localize2 } from '../../../../../nls.js'; import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js'; @@ -24,7 +21,6 @@ import { IUntitledTextResourceEditorInput } from '../../../../common/editor.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { accessibleViewInCodeBlock } from '../../../accessibility/browser/accessibilityConfiguration.js'; import { ITerminalEditorService, ITerminalGroupService, ITerminalService } from '../../../terminal/browser/terminal.js'; -import { ICodeMapperCodeBlock, ICodeMapperService } from '../../common/chatCodeMapperService.js'; import { CONTEXT_CHAT_EDIT_APPLIED, CONTEXT_CHAT_ENABLED, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION } from '../../common/chatContextKeys.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; import { ChatCopyKind, IChatService } from '../../common/chatService.js'; @@ -235,41 +231,21 @@ export function registerChatCodeBlockActions() { override async run(accessor: ServicesAccessor, ...args: any[]) { const chatWidgetService = accessor.get(IChatWidgetService); - const codemapperService = accessor.get(ICodeMapperService); const chatEditingService = accessor.get(IChatEditingService); const widget = chatWidgetService.lastFocusedWidget; - if (!widget) { + if (!widget || !widget.viewModel) { return; } - const items = widget.viewModel?.getItems() ?? []; - const item = widget.getFocus() ?? items[items.length - 1]; - if (!isResponseVM(item)) { - return; - } + const applyEditsId = args[0]; - const codeblocks = widget.getCodeBlockInfosForResponse(item); - const request: ICodeMapperCodeBlock[] = []; - for (const codeblock of codeblocks) { - if (codeblock.codemapperUri && codeblock.uri) { - const code = codeblock.getContent(); - request.push({ resource: codeblock.codemapperUri, code }); - } + const chatModel = widget.viewModel.model; + const request = chatModel.getRequests().find(request => request.response?.result?.metadata?.applyEditsId === applyEditsId); + if (request && request.response) { + await chatEditingService.startOrContinueEditingSession(widget.viewModel.sessionId, { silent: true }); // make sure we have an editing session + await chatEditingService.triggerEditComputation(request.response); } - - await chatEditingService.startOrContinueEditingSession(item.sessionId, async (stream) => { - - const response = { - textEdit: (resource: URI, textEdits: TextEdit[]) => { - stream.textEdits(resource, textEdits); - } - }; - - // Invoke the code mapper for all the code blocks in this response - const tokenSource = new CancellationTokenSource(); - await codemapperService.mapCode({ codeBlocks: request, conversation: [] }, response, tokenSource.token); - }, { silent: true }); } }); diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index d2e2216540fba..efa5e7a30e745 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -188,7 +188,7 @@ class AttachContextAction extends Action2 { title: localize2('workbench.action.chat.attachContext.label', "Attach Context"), icon: Codicon.attach, category: CHAT_CATEGORY, - precondition: AttachContextAction._cdt, + precondition: ContextKeyExpr.or(AttachContextAction._cdt, ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession))), keybinding: { when: CONTEXT_IN_CHAT_INPUT, primary: KeyMod.CtrlCmd | KeyCode.Slash, @@ -196,7 +196,7 @@ class AttachContextAction extends Action2 { }, menu: [ { - when: ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Panel), AttachContextAction._cdt), + when: ContextKeyExpr.or(ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession)), ContextKeyExpr.and(ContextKeyExpr.or(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Panel), CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession)), AttachContextAction._cdt)), id: MenuId.ChatInput, group: 'navigation', order: 2 diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts index fdff4f2c19797..94d12546a42c3 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts @@ -167,7 +167,7 @@ export class CancelAction extends Action2 { menu: { id: MenuId.ChatExecute, when: CONTEXT_CHAT_REQUEST_IN_PROGRESS, - order: 2, + order: 4, group: 'navigation', }, keybinding: { diff --git a/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.ts b/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.ts index e4d58e6fdea9e..161860a4efc64 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.ts @@ -8,15 +8,13 @@ import { VSBuffer } from '../../../../../base/common/buffer.js'; import { CancellationTokenSource } from '../../../../../base/common/cancellation.js'; import { CharCode } from '../../../../../base/common/charCode.js'; import { isCancellationError } from '../../../../../base/common/errors.js'; -import { ResourceMap } from '../../../../../base/common/map.js'; import { isEqual } from '../../../../../base/common/resources.js'; import * as strings from '../../../../../base/common/strings.js'; -import { URI } from '../../../../../base/common/uri.js'; import { IActiveCodeEditor, isCodeEditor, isDiffEditor } from '../../../../../editor/browser/editorBrowser.js'; import { IBulkEditService, ResourceTextEdit } from '../../../../../editor/browser/services/bulkEditService.js'; import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; import { Range } from '../../../../../editor/common/core/range.js'; -import { ConversationRequest, ConversationResponse, DocumentContextItem, isLocation, IWorkspaceFileEdit, IWorkspaceTextEdit } from '../../../../../editor/common/languages.js'; +import { ConversationRequest, ConversationResponse, DocumentContextItem, IWorkspaceFileEdit, IWorkspaceTextEdit } from '../../../../../editor/common/languages.js'; import { ILanguageService } from '../../../../../editor/common/languages/language.js'; import { ITextModel } from '../../../../../editor/common/model.js'; import { ILanguageFeaturesService } from '../../../../../editor/common/services/languageFeatures.js'; @@ -31,7 +29,8 @@ import { InlineChatController } from '../../../inlineChat/browser/inlineChatCont import { insertCell } from '../../../notebook/browser/controller/cellOperations.js'; import { IActiveNotebookEditor, INotebookEditor } from '../../../notebook/browser/notebookBrowser.js'; import { CellKind, NOTEBOOK_EDITOR_ID } from '../../../notebook/common/notebookCommon.js'; -import { ChatUserAction, IChatContentReference, IChatService } from '../../common/chatService.js'; +import { getReferencesAsDocumentContext } from '../../common/chatCodeMapperService.js'; +import { ChatUserAction, IChatService } from '../../common/chatService.js'; import { isRequestVM, isResponseVM } from '../../common/chatViewModel.js'; import { ICodeBlockActionContext } from '../codeBlockPart.js'; @@ -404,32 +403,6 @@ function getChatConversation(context: ICodeBlockActionContext): (ConversationReq } } -function getReferencesAsDocumentContext(res: readonly IChatContentReference[]): DocumentContextItem[] { - const map = new ResourceMap(); - for (const r of res) { - let uri; - let range; - if (URI.isUri(r.reference)) { - uri = r.reference; - } else if (isLocation(r.reference)) { - uri = r.reference.uri; - range = r.reference.range; - } - if (uri) { - const item = map.get(uri); - if (item) { - if (range) { - item.ranges.push(range); - } - } else { - map.set(uri, { uri, version: -1, ranges: range ? [range] : [] }); - } - } - } - return [...map.values()]; -} - - function reindent(codeBlockContent: string, model: ITextModel, seletionStartLine: number): string { const newContent = strings.splitLines(codeBlockContent); if (newContent.length === 0) { diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index bec60f8fd124a..dda6330c614ac 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { timeout } from '../../../../base/common/async.js'; import { MarkdownString, isMarkdownString } from '../../../../base/common/htmlContent.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { Schemas } from '../../../../base/common/network.js'; @@ -263,6 +264,11 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable { progress.report({ content: new MarkdownString(defaultAgent.metadata.helpTextPostfix), kind: 'markdownContent' }); } } + + // Without this, the response will be done before it renders and so it will not stream. This ensures that if the response starts + // rendering during the next 200ms, then it will be streamed. Once it starts streaming, the whole response streams even after + // it has received all response data has been received. + await timeout(200); })); } } diff --git a/src/vs/workbench/contrib/chat/browser/chat.ts b/src/vs/workbench/contrib/chat/browser/chat.ts index 25fa010281fbe..cab43391c45ef 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.ts @@ -36,12 +36,17 @@ export interface IChatWidgetService { getWidgetByInputUri(uri: URI): IChatWidget | undefined; getWidgetBySessionId(sessionId: string): IChatWidget | undefined; + getWidgetByLocation(location: ChatAgentLocation): IChatWidget[]; } export async function showChatView(viewsService: IViewsService): Promise { return (await viewsService.openView(CHAT_VIEW_ID))?.widget; } +export async function showEditsView(viewsService: IViewsService): Promise { + return (await viewsService.openView(EDITS_VIEW_ID))?.widget; +} + export const IQuickChatService = createDecorator('quickChatService'); export interface IQuickChatService { readonly _serviceBrand: undefined; @@ -108,6 +113,7 @@ export interface IChatWidgetViewOptions { renderFollowups?: boolean; renderStyle?: 'compact' | 'minimal'; supportsFileReferences?: boolean; + supportsAdditionalParticipants?: boolean; filter?: (item: ChatTreeItem) => boolean; rendererOptions?: IChatListItemRendererOptions; menus?: { @@ -195,3 +201,5 @@ export interface IChatCodeBlockContextProviderService { export const GeneratingPhrase = localize('generating', "Generating"); export const CHAT_VIEW_ID = `workbench.panel.chat.view.${CHAT_PROVIDER_ID}`; + +export const EDITS_VIEW_ID = 'workbench.panel.chat.view.edits'; diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts index b81634ce4c42e..cc15830cd2608 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts @@ -133,17 +133,19 @@ export class ChatAttachmentsContentPart extends Disposable { if (file) { widget.style.cursor = 'pointer'; - this.attachedContextDisposables.add(dom.addDisposableListener(widget, dom.EventType.CLICK, async (e: MouseEvent) => { - dom.EventHelper.stop(e, true); - this.openerService.open( - file, - { - fromUserGesture: true, - editorOptions: { - selection: range - } as any - }); - })); + if (!this.attachedContextDisposables.isDisposed) { + this.attachedContextDisposables.add(dom.addDisposableListener(widget, dom.EventType.CLICK, async (e: MouseEvent) => { + dom.EventHelper.stop(e, true); + this.openerService.open( + file, + { + fromUserGesture: true, + editorOptions: { + selection: range + } as any + }); + })); + } } widget.ariaLabel = ariaLabel; diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatMarkdownContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatMarkdownContentPart.ts index 552f7522e7676..1d7731a17b704 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatMarkdownContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatMarkdownContentPart.ts @@ -26,6 +26,8 @@ import { IChatProgressRenderableResponseContent } from '../../common/chatModel.j import { isRequestVM, isResponseVM } from '../../common/chatViewModel.js'; import { CodeBlockModelCollection } from '../../common/codeBlockModelCollection.js'; import { URI } from '../../../../../base/common/uri.js'; +import { IEditorService } from '../../../../services/editor/common/editorService.js'; +import { InlineAnchorWidget } from '../chatInlineAnchorWidget.js'; const $ = dom.$; @@ -52,7 +54,8 @@ export class ChatMarkdownContentPart extends Disposable implements IChatContentP rendererOptions: IChatListItemRendererOptions, @IContextKeyService contextKeyService: IContextKeyService, @ITextModelService private readonly textModelService: ITextModelService, - @IInstantiationService instantiationService: IInstantiationService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IEditorService private readonly editorService: IEditorService, ) { super(); @@ -132,6 +135,7 @@ export class ChatMarkdownContentPart extends Disposable implements IChatContentP this.codeBlockModelCollection.update(data.element.sessionId, data.element, data.codeBlockIndex, { text, languageId: data.languageId }).then((e) => { // Update the existing object's codemapperUri this.codeblocks[data.codeBlockIndex].codemapperUri = e.codemapperUri; + this._onDidChangeHeight.fire(); }); } @@ -145,7 +149,20 @@ export class ChatMarkdownContentPart extends Disposable implements IChatContentP } layout(width: number): void { - this.allRefs.forEach(ref => ref.object.layout(width)); + this.allRefs.forEach((ref, index) => { + const codeblockModel = this.codeblocks[index]; + if (codeblockModel.codemapperUri) { + const fileWidgetAnchor = $('.chat-codeblock'); + this._register(this.instantiationService.createInstance(InlineAnchorWidget, fileWidgetAnchor, { uri: codeblockModel.codemapperUri }, { handleClick: (uri) => this.editorService.openEditor({ resource: uri }) })); + const existingCodeblock = ref.object.element.parentElement?.querySelector('.chat-codeblock'); + if (!existingCodeblock) { + ref.object.element.parentElement?.appendChild(fileWidgetAnchor); + ref.object.element.style.display = 'none'; + } + } else { + ref.object.layout(width); + } + }); } addDisposable(disposable: IDisposable): void { diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts index 2ca9d305f544d..0c31726d04843 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts @@ -6,6 +6,7 @@ import * as dom from '../../../../../base/browser/dom.js'; import { Button } from '../../../../../base/browser/ui/button/button.js'; import { IListRenderer, IListVirtualDelegate } from '../../../../../base/browser/ui/list/list.js'; +import { IAction } from '../../../../../base/common/actions.js'; import { coalesce } from '../../../../../base/common/arrays.js'; import { Codicon } from '../../../../../base/common/codicons.js'; import { Emitter, Event } from '../../../../../base/common/event.js'; @@ -15,13 +16,13 @@ import { basename } from '../../../../../base/common/path.js'; import { basenameOrAuthority, isEqualAuthority } from '../../../../../base/common/resources.js'; import { ThemeIcon } from '../../../../../base/common/themables.js'; import { URI } from '../../../../../base/common/uri.js'; -import { localize } from '../../../../../nls.js'; +import { localize, localize2 } from '../../../../../nls.js'; +import { createAndFillInContextMenuActions } from '../../../../../platform/actions/browser/menuEntryActionViewItem.js'; import { MenuWorkbenchToolBar } from '../../../../../platform/actions/browser/toolbar.js'; -import { MenuId } from '../../../../../platform/actions/common/actions.js'; -import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js'; +import { Action2, IMenuService, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js'; import { IContextMenuService } from '../../../../../platform/contextview/browser/contextView.js'; import { FileKind } from '../../../../../platform/files/common/files.js'; -import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; +import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; import { WorkbenchList } from '../../../../../platform/list/browser/listService.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; @@ -30,12 +31,14 @@ import { IThemeService } from '../../../../../platform/theme/common/themeService import { fillEditorsDragData } from '../../../../browser/dnd.js'; import { IResourceLabel, ResourceLabels } from '../../../../browser/labels.js'; import { ColorScheme } from '../../../../browser/web.api.js'; +import { ResourceContextKey } from '../../../../common/contextkeys.js'; import { SETTINGS_AUTHORITY } from '../../../../services/preferences/common/preferences.js'; import { createFileIconThemableTreeContainerScope } from '../../../files/browser/views/explorerView.js'; +import { ExplorerFolderContext } from '../../../files/common/files.js'; import { ChatResponseReferencePartStatusKind, IChatContentReference, IChatWarningMessage } from '../../common/chatService.js'; import { IChatVariablesService } from '../../common/chatVariables.js'; import { IChatRendererContent, IChatResponseViewModel } from '../../common/chatViewModel.js'; -import { ChatTreeItem } from '../chat.js'; +import { ChatTreeItem, IChatWidgetService } from '../chat.js'; import { IDisposableReference, ResourcePool } from './chatCollections.js'; import { IChatContentPart } from './chatContentParts.js'; @@ -59,8 +62,9 @@ export class ChatCollapsibleListContentPart extends Disposable implements IChatC element: IChatResponseViewModel, contentReferencesListPool: CollapsibleListPool, @IOpenerService openerService: IOpenerService, + @IMenuService menuService: IMenuService, + @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IClipboardService private readonly clipboardService: IClipboardService, ) { super(); @@ -120,34 +124,32 @@ export class ChatCollapsibleListContentPart extends Disposable implements IChatC } } })); - this._register(list.onContextMenu((e) => { - e.browserEvent.preventDefault(); - e.browserEvent.stopPropagation(); - if (e.element && 'reference' in e.element && typeof e.element.reference === 'object') { - const uriOrLocation = 'variableName' in e.element.reference ? e.element.reference.value : e.element.reference; - const uri = URI.isUri(uriOrLocation) ? uriOrLocation : - uriOrLocation?.uri; - if (uri) { - this.contextMenuService.showContextMenu({ - getAnchor: () => e.anchor, - getActions: () => { - return [{ - id: 'workbench.action.chat.copyReference', - title: localize('copyReference', "Copy"), - label: localize('copyReference', "Copy"), - tooltip: localize('copyReference', "Copy"), - enabled: e.element?.kind === 'reference', - class: undefined, - run: () => { - void this.clipboardService.writeResources([uri]); - } - }]; - } - }); - } + this._register(list.onContextMenu(e => { + dom.EventHelper.stop(e.browserEvent, true); + + const uri = e.element && getResourceForElement(e.element); + if (!uri) { + return; } + this.contextMenuService.showContextMenu({ + getAnchor: () => e.anchor, + getActions: () => { + const menu = menuService.getMenuActions(MenuId.ChatAttachmentsContext, list.contextKeyService, { shouldForwardArgs: true, arg: uri }); + const primary: IAction[] = []; + createAndFillInContextMenuActions(menu, primary); + return primary; + } + }); + })); + + const resourceContextKey = this._register(this.instantiationService.createInstance(ResourceContextKey)); + this._register(list.onDidChangeFocus(e => { + resourceContextKey.reset(); + const element = e.elements.length ? e.elements[0] : undefined; + const uri = element && getResourceForElement(element); + resourceContextKey.set(uri ?? null); })); const maxItemsShown = 6; @@ -197,20 +199,6 @@ export class CollapsibleListPool extends Disposable { const container = $('.chat-used-context-list'); this._register(createFileIconThemableTreeContainerScope(container, this.themeService)); - const getDragURI = (element: IChatCollapsibleListItem): URI | null => { - if (element.kind === 'warning') { - return null; - } - const { reference } = element; - if (typeof reference === 'string' || 'variableName' in reference) { - return null; - } else if (URI.isUri(reference)) { - return reference; - } else { - return reference.uri; - } - }; - const list = this.instantiationService.createInstance( WorkbenchList, 'ChatListRenderer', @@ -239,9 +227,9 @@ export class CollapsibleListPool extends Disposable { getWidgetAriaLabel: () => localize('chatCollapsibleList', "Collapsible Chat List") }, dnd: { - getDragURI: (element: IChatCollapsibleListItem) => getDragURI(element)?.toString() ?? null, + getDragURI: (element: IChatCollapsibleListItem) => getResourceForElement(element)?.toString() ?? null, getDragLabel: (elements, originalEvent) => { - const uris: URI[] = coalesce(elements.map(getDragURI)); + const uris: URI[] = coalesce(elements.map(getResourceForElement)); if (!uris.length) { return undefined; } else if (uris.length === 1) { @@ -256,7 +244,7 @@ export class CollapsibleListPool extends Disposable { onDragStart: (data, originalEvent) => { try { const elements = data.getData() as IChatCollapsibleListItem[]; - const uris: URI[] = coalesce(elements.map(getDragURI)); + const uris: URI[] = coalesce(elements.map(getResourceForElement)); this.instantiationService.invokeFunction(accessor => fillEditorsDragData(accessor, uris, originalEvent)); } catch { // noop @@ -294,8 +282,8 @@ class CollapsibleListDelegate implements IListVirtualDelegate { @@ -414,3 +402,58 @@ class CollapsibleListRenderer implements IListRenderer { + const chatWidgetService = accessor.get(IChatWidgetService); + const variablesService = accessor.get(IChatVariablesService); + + if (!resource) { + return; + } + + const widget = chatWidgetService.lastFocusedWidget; + if (!widget) { + return; + } + + variablesService.attachContext('file', resource, widget.location); + } +}); + +//#endregion diff --git a/src/vs/workbench/contrib/chat/browser/chatEditingService.ts b/src/vs/workbench/contrib/chat/browser/chatEditingService.ts index 23878a50926a2..14874cf40adf9 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditingService.ts @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { Sequencer } from '../../../../base/common/async.js'; +import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js'; import { Codicon } from '../../../../base/common/codicons.js'; import { BugIndicatingError } from '../../../../base/common/errors.js'; import { Emitter } from '../../../../base/common/event.js'; -import { Disposable, IReference, MutableDisposable } from '../../../../base/common/lifecycle.js'; -import { Schemas } from '../../../../base/common/network.js'; +import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable } from '../../../../base/common/lifecycle.js'; import { derived, IObservable, ITransaction, observableValue, ValueWithChangeEventFromObservable } from '../../../../base/common/observable.js'; import { URI } from '../../../../base/common/uri.js'; -import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { IBulkEditService } from '../../../../editor/browser/services/bulkEditService.js'; import { TextEdit } from '../../../../editor/common/languages.js'; import { ILanguageService } from '../../../../editor/common/languages/language.js'; @@ -30,17 +29,14 @@ import { DiffEditorInput } from '../../../common/editor/diffEditorInput.js'; import { EditorInput } from '../../../common/editor/editorInput.js'; import { IEditorGroup, IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; -import { IViewsService } from '../../../services/views/common/viewsService.js'; import { MultiDiffEditor } from '../../multiDiffEditor/browser/multiDiffEditor.js'; import { MultiDiffEditorInput } from '../../multiDiffEditor/browser/multiDiffEditorInput.js'; import { IMultiDiffSourceResolver, IMultiDiffSourceResolverService, IResolvedMultiDiffSource, MultiDiffEditorItem } from '../../multiDiffEditor/browser/multiDiffSourceResolverService.js'; -import { ChatAgentLocation } from '../common/chatAgents.js'; -import { CONTEXT_CHAT_EDITING_ENABLED, CONTEXT_CHAT_ENABLED } from '../common/chatContextKeys.js'; +import { ICodeMapperResponse, ICodeMapperService } from '../common/chatCodeMapperService.js'; import { ChatEditingSessionState, IChatEditingService, IChatEditingSession, IChatEditingSessionStream, IModifiedFileEntry, ModifiedFileEntryState } from '../common/chatEditingService.js'; +import { IChatResponseModel } from '../common/chatModel.js'; import { IChatService } from '../common/chatService.js'; -import { IChatVariablesService } from '../common/chatVariables.js'; -import { CHAT_CATEGORY } from './actions/chatActions.js'; -import { CHAT_VIEW_ID, IChatWidgetService, showChatView } from './chat.js'; +import { IChatWidgetService } from './chat.js'; const decidedChatEditingResourceContextKey = new RawContextKey('decidedChatEditingResource', []); const chatEditingResourceContextKey = new RawContextKey('chatEditingResource', undefined); @@ -70,6 +66,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic @IContextKeyService contextKeyService: IContextKeyService, @IChatService private readonly _chatService: IChatService, @IProgressService private readonly _progressService: IProgressService, + @ICodeMapperService private readonly _codeMapperService: ICodeMapperService, ) { super(); this._register(multiDiffSourceResolverService.registerResolver(_instantiationService.createInstance(ChatEditingMultiDiffSourceResolver, this._currentSessionObs))); @@ -95,24 +92,24 @@ export class ChatEditingService extends Disposable implements IChatEditingServic super.dispose(); } - async startOrContinueEditingSession(chatSessionId: string, builder?: (stream: IChatEditingSessionStream) => Promise, options?: { silent: boolean }): Promise { + async startOrContinueEditingSession(chatSessionId: string, options?: { silent: boolean }): Promise { const session = this._currentSessionObs.get(); if (session) { if (session.chatSessionId !== chatSessionId) { throw new BugIndicatingError('Cannot start new session while another session is active'); } - if (builder) { - return this._continueEditingSession(builder, options); - } } - return this._createEditingSession(chatSessionId, builder, options); + return this._createEditingSession(chatSessionId, options); } - private async _createEditingSession(chatSessionId: string, builder?: (stream: IChatEditingSessionStream) => Promise, options?: { silent: boolean }): Promise { + private async _createEditingSession(chatSessionId: string, options?: { silent: boolean }): Promise { if (this._currentSessionObs.get()) { throw new BugIndicatingError('Cannot have more than one active editing session'); } + // listen for completed responses, run the code mapper and apply the edits to this edit session + this._register(this.installAutoApplyObserver(chatSessionId)); + const input = MultiDiffEditorInput.fromResourceMultiDiffEditorInput({ multiDiffSource: ChatEditingMultiDiffSourceResolver.getMultiDiffSourceUri(), label: localize('multiDiffEditorInput.name', "Suggested Edits") @@ -128,13 +125,57 @@ export class ChatEditingService extends Disposable implements IChatEditingServic this._currentSessionObs.set(session, undefined); this._onDidCreateEditingSession.fire(session); + return session; + } - if (builder) { - return this._continueEditingSession(builder, options); + public triggerEditComputation(responseModel: IChatResponseModel): Promise { + return this._continueEditingSession(async (builder, token) => { + const codeMapperResponse: ICodeMapperResponse = { + textEdit: (resource, edits) => builder.textEdits(resource, edits), + }; + await this._codeMapperService.mapCodeFromResponse(responseModel, codeMapperResponse, token); + }, { silent: true }); + } + + private installAutoApplyObserver(sessionId: string): IDisposable { + + const chatModel = this._chatService.getSession(sessionId); + if (!chatModel) { + throw new Error(`Edit session was created for a non-existing chat session: ${sessionId}`); } + + const observerDisposables = new DisposableStore(); + + const onResponseComplete = (responseModel: IChatResponseModel) => { + if (responseModel.result?.metadata?.autoApplyEdits) { + this.triggerEditComputation(responseModel); + } + }; + + observerDisposables.add(chatModel.onDidChange(e => { + if (e.kind === 'addRequest') { + const responseModel = e.request.response; + if (responseModel) { + if (responseModel.isComplete) { + onResponseComplete(responseModel); + } else { + const disposable = responseModel.onDidChange(() => { + if (responseModel.isComplete) { + onResponseComplete(responseModel); + disposable.dispose(); + } else if (responseModel.isCanceled || responseModel.isStale) { + disposable.dispose(); + } + }); + } + } + } + })); + observerDisposables.add(chatModel.onDidDispose(() => observerDisposables.dispose())); + return observerDisposables; } - private async _continueEditingSession(builder: (stream: IChatEditingSessionStream) => Promise, options?: { silent?: boolean }): Promise { + private async _continueEditingSession(builder: (stream: IChatEditingSessionStream, token: CancellationToken) => Promise, options?: { silent?: boolean }): Promise { const session = this._currentSessionObs.get(); if (!session) { throw new BugIndicatingError('Cannot continue missing session'); @@ -161,18 +202,22 @@ export class ChatEditingService extends Disposable implements IChatEditingServic } }; session.acceptStreamingEditsStart(); + const cancellationTokenSource = new CancellationTokenSource(); try { if (editorPane) { - await editorPane?.showWhile(builder(stream)); + await editorPane?.showWhile(builder(stream, cancellationTokenSource.token)); } else { await this._progressService.withProgress({ location: ProgressLocation.Window, title: localize2('chatEditing.startingSession', 'Generating edits...').value, }, async () => { - await builder(stream); - }); + await builder(stream, cancellationTokenSource.token); + }, + () => cancellationTokenSource.cancel() + ); } } finally { + cancellationTokenSource.dispose(); session.resolve(); } } @@ -421,74 +466,6 @@ export class ChatEditingDiscardAllAction extends Action2 { } registerAction2(ChatEditingDiscardAllAction); -export class ChatEditingStartSessionAction extends Action2 { - static readonly ID = 'chatEditing.startSession'; - static readonly LABEL = localize2('chatEditing.startSession', 'Start Editing Session'); - - constructor() { - super({ - id: ChatEditingStartSessionAction.ID, - title: ChatEditingStartSessionAction.LABEL, - category: CHAT_CATEGORY, - icon: Codicon.edit, - precondition: CONTEXT_CHAT_ENABLED, - f1: true, - menu: [{ - id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', CHAT_VIEW_ID), CONTEXT_CHAT_EDITING_ENABLED), - group: 'navigation', - order: 1 - }] - }); - } - - async run(accessor: ServicesAccessor, ...args: any[]): Promise { - const textEditorService = accessor.get(IEditorService); - const variablesService = accessor.get(IChatVariablesService); - const chatEditingService = accessor.get(IChatEditingService); - const chatWidgetService = accessor.get(IChatWidgetService); - const viewsService = accessor.get(IViewsService); - - const currentEditingSession = chatEditingService.currentEditingSession; - if (currentEditingSession) { - return; - } - const widget = chatWidgetService.lastFocusedWidget ?? await showChatView(viewsService); - if (!widget?.viewModel) { - return; - } - - const visibleTextEditorControls = textEditorService.visibleTextEditorControls.filter((e) => isCodeEditor(e)); - visibleTextEditorControls.forEach((e) => { - const activeUri = e.getModel()?.uri; - if (activeUri && [Schemas.file, Schemas.vscodeRemote, Schemas.untitled].includes(activeUri.scheme)) { - variablesService.attachContext('file', { uri: activeUri, }, ChatAgentLocation.Panel); - } - }); - await chatEditingService.startOrContinueEditingSession(widget.viewModel.sessionId, undefined, { silent: true }); - } -} -registerAction2(ChatEditingStartSessionAction); -export class ChatEditingStopSessionAction extends Action2 { - static readonly ID = 'chatEditing.stopSession'; - static readonly LABEL = localize2('chatEditing.stopSession', 'Stop Editing Session'); - - constructor() { - super({ - id: ChatEditingStopSessionAction.ID, - title: ChatEditingStopSessionAction.LABEL, - category: CHAT_CATEGORY, - f1: true - }); - } - - async run(accessor: ServicesAccessor, ...args: any[]): Promise { - const chatEditingService = accessor.get(IChatEditingService); - await chatEditingService.currentEditingSession?.stop(); - } -} -registerAction2(ChatEditingStopSessionAction); - export class ChatEditingShowChangesAction extends Action2 { static readonly ID = 'chatEditing.openDiffs'; static readonly LABEL = localize('chatEditing.openDiffs', 'Open Diffs'); @@ -597,6 +574,7 @@ class ChatEditingSession extends Disposable implements IChatEditingSession { @ITextModelService private readonly _textModelService: ITextModelService, @IBulkEditService public readonly _bulkEditService: IBulkEditService, @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, + @IEditorService private readonly editorService: IEditorService, ) { super(); } @@ -672,7 +650,11 @@ class ChatEditingSession extends Disposable implements IChatEditingSession { })); })); - this.dispose(); + if (this._state.get() !== ChatEditingSessionState.Disposed) { + // session got disposed while we were closing editors + this.dispose(); + } + } override dispose() { @@ -727,7 +709,8 @@ class ChatEditingSession extends Disposable implements IChatEditingSession { private async _acceptTextEdits(resource: URI, textEdits: TextEdit[]): Promise { const entry = await this._getOrCreateModifiedFileEntry(resource); - entry.appyEdits(textEdits); + entry.applyEdits(textEdits); + await this.editorService.openEditor({ original: { resource: entry.originalURI }, modified: { resource: entry.modifiedURI }, options: { inactive: true } }); } private async _resolve(): Promise { @@ -815,7 +798,7 @@ class ModifiedFileEntry extends Disposable implements IModifiedFileEntry { this._register(resourceRef); } - appyEdits(textEdits: TextEdit[]): void { + applyEdits(textEdits: TextEdit[]): void { this.doc.applyEdits(textEdits); this._stateObs.set(ModifiedFileEntryState.Undecided, undefined); } diff --git a/src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts b/src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts index bb24ba0946c53..41a39c9aa88ae 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts @@ -40,9 +40,12 @@ import { IChatWidgetService } from './chat.js'; export class InlineAnchorWidget extends Disposable { + public static readonly className = 'chat-inline-anchor-widget'; + constructor( - element: HTMLAnchorElement, + element: HTMLAnchorElement | HTMLElement, data: ContentRefData, + options: { handleClick?: (uri: URI) => void } = {}, @IContextKeyService originalContextKeyService: IContextKeyService, @IContextMenuService contextMenuService: IContextMenuService, @IFileService fileService: IFileService, @@ -60,7 +63,10 @@ export class InlineAnchorWidget extends Disposable { const contextKeyService = this._register(originalContextKeyService.createScoped(element)); const anchorId = new Lazy(generateUuid); - element.classList.add('chat-inline-anchor-widget', 'show-file-icons'); + element.classList.add(InlineAnchorWidget.className, 'show-file-icons'); + if (options.handleClick) { + element.classList.add('clickable'); + } let iconText: string; let iconClasses: string[]; @@ -128,6 +134,8 @@ export class InlineAnchorWidget extends Disposable { .catch(() => { }); this._register(dom.addDisposableListener(element, 'click', () => { + options.handleClick?.(location.uri); + telemetryService.publicLog2<{ anchorId: string; }, { diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index f26327ce23a9b..fd2a0aeabb2ba 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -838,10 +838,10 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge hoverElement.appendChild(img); } - async renderChatEditingSessionState(chatEditingSession: IChatEditingSession | null) { - dom.setVisibility(Boolean(chatEditingSession), this.chatEditingSessionWidgetContainer); + async renderChatEditingSessionState(chatEditingSession: IChatEditingSession | null, initialState?: boolean) { + dom.setVisibility(Boolean(chatEditingSession) || Boolean(initialState), this.chatEditingSessionWidgetContainer); - if (!chatEditingSession) { + if (!chatEditingSession && !initialState) { dom.clearNode(this.chatEditingSessionWidgetContainer); this._chatEditsDisposables.clear(); this._chatEditList = undefined; @@ -850,7 +850,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge return; } - if (this._chatEditList && chatEditingSession.state.get() === ChatEditingSessionState.Idle) { + if (this._chatEditList && chatEditingSession?.state.get() === ChatEditingSessionState.Idle) { this._chatEditsProgress?.stop(); this._chatEditsProgress?.dispose(); this._chatEditsProgress = undefined; @@ -858,7 +858,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge // Summary of number of files changed const innerContainer = this.chatEditingSessionWidgetContainer.querySelector('.chat-editing-session-container.show-file-icons') as HTMLElement ?? dom.append(this.chatEditingSessionWidgetContainer, $('.chat-editing-session-container.show-file-icons')); - const numberOfEditedEntries = chatEditingSession.entries.get().length; + const numberOfEditedEntries = chatEditingSession?.entries.get().length ?? 0; const overviewRegion = innerContainer.querySelector('.chat-editing-session-overview') as HTMLElement ?? dom.append(innerContainer, $('.chat-editing-session-overview')); if (numberOfEditedEntries !== this._chatEditList?.object.length) { const overviewText = overviewRegion.querySelector('span') ?? dom.append(overviewRegion, $('span')); @@ -867,6 +867,10 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge : localize('chatEditingSessionOverview', "{0} files changed", numberOfEditedEntries); } + if (!chatEditingSession) { + return; + } + //#region Chat editing session actions { const actionsContainer = overviewRegion.querySelector('.chat-editing-session-actions') as HTMLElement ?? dom.append(overviewRegion, $('.chat-editing-session-actions')); diff --git a/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts index 79555a8099fe2..43ed2cc5a5bf6 100644 --- a/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts @@ -246,7 +246,7 @@ export class ChatMarkdownDecorationsRenderer extends Disposable { return; } - store.add(this.instantiationService.createInstance(InlineAnchorWidget, a, data)); + store.add(this.instantiationService.createInstance(InlineAnchorWidget, a, data, undefined)); } private renderResourceWidget(name: string, args: IDecorationWidgetArgs | undefined, store: DisposableStore): HTMLElement { diff --git a/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts b/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts index 05f89e7f97285..8f9a2e9195b97 100644 --- a/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts @@ -23,10 +23,10 @@ import * as extensionsRegistry from '../../../services/extensions/common/extensi import { showExtensionsWithIdsCommandId } from '../../extensions/browser/extensionsActions.js'; import { IExtension, IExtensionsWorkbenchService } from '../../extensions/common/extensions.js'; import { ChatAgentLocation, IChatAgentData, IChatAgentService } from '../common/chatAgents.js'; -import { CONTEXT_CHAT_EXTENSION_INVALID, CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED } from '../common/chatContextKeys.js'; +import { CONTEXT_CHAT_EDITING_PARTICIPANT_REGISTERED, CONTEXT_CHAT_EXTENSION_INVALID, CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED } from '../common/chatContextKeys.js'; import { IRawChatParticipantContribution } from '../common/chatParticipantContribTypes.js'; import { CHAT_VIEW_ID } from './chat.js'; -import { CHAT_SIDEBAR_PANEL_ID, ChatViewPane } from './chatViewPane.js'; +import { CHAT_EDITING_SIDEBAR_PANEL_ID, CHAT_SIDEBAR_PANEL_ID, ChatViewPane } from './chatViewPane.js'; const chatParticipantExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'chatParticipants', @@ -175,6 +175,7 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution { ) { this._viewContainer = this.registerViewContainer(); this.registerDefaultParticipantView(); + this.registerChatEditingView(); this.handleAndRegisterChatExtensions(); } @@ -316,6 +317,40 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution { Registry.as(ViewExtensions.ViewsRegistry).deregisterViews(viewDescriptor, this._viewContainer); }); } + + private registerChatEditingView(): IDisposable { + const title = localize2('chatEditing.viewContainer.label', "Copilot Edits"); + const icon = Codicon.requestChanges; + const viewContainerId = CHAT_EDITING_SIDEBAR_PANEL_ID; + const viewContainer: ViewContainer = Registry.as(ViewExtensions.ViewContainersRegistry).registerViewContainer({ + id: viewContainerId, + title, + icon, + ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [viewContainerId, { mergeViewWithContainerWhenSingleView: true }]), + storageId: viewContainerId, + hideIfEmpty: true, + order: 100, + }, ViewContainerLocation.AuxiliaryBar); + + const id = 'workbench.panel.chat.view.edits'; + const viewDescriptor: IViewDescriptor[] = [{ + id: id, + containerIcon: viewContainer.icon, + containerTitle: title.value, + singleViewPaneContainerTitle: title.value, + name: { value: title.value, original: title.value }, + canToggleVisibility: false, + canMoveView: true, + ctorDescriptor: new SyncDescriptor(ChatViewPane, [{ id, title: title.value }, { location: ChatAgentLocation.EditingSession }]), + when: CONTEXT_CHAT_EDITING_PARTICIPANT_REGISTERED + }]; + Registry.as(ViewExtensions.ViewsRegistry).registerViews(viewDescriptor, viewContainer); + + return toDisposable(() => { + Registry.as(ViewExtensions.ViewContainersRegistry).deregisterViewContainer(viewContainer); + Registry.as(ViewExtensions.ViewsRegistry).deregisterViews(viewDescriptor, viewContainer); + }); + } } function getParticipantKey(extensionId: ExtensionIdentifier, participantName: string): string { diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index 9493af1a04ff4..19b0ee18b0f89 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -34,6 +34,7 @@ interface IViewPaneState extends IChatViewState { } export const CHAT_SIDEBAR_PANEL_ID = 'workbench.panel.chatSidebar'; +export const CHAT_EDITING_SIDEBAR_PANEL_ID = 'workbench.panel.chatEditing'; export class ChatViewPane extends ViewPane { private _widget!: ChatWidget; get widget(): ChatWidget { return this._widget; } @@ -48,6 +49,7 @@ export class ChatViewPane extends ViewPane { constructor( options: IViewPaneOptions, + private readonly chatOptions: { location: ChatAgentLocation.Panel | ChatAgentLocation.EditingSession } = { location: ChatAgentLocation.Panel }, @IKeybindingService keybindingService: IKeybindingService, @IContextMenuService contextMenuService: IContextMenuService, @IConfigurationService configurationService: IConfigurationService, @@ -66,11 +68,11 @@ export class ChatViewPane extends ViewPane { super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService, hoverService); // View state for the ViewPane is currently global per-provider basically, but some other strictly per-model state will require a separate memento. - this.memento = new Memento('interactive-session-view-' + CHAT_PROVIDER_ID, this.storageService); + this.memento = new Memento('interactive-session-view-' + CHAT_PROVIDER_ID + (this.chatOptions.location === ChatAgentLocation.EditingSession ? `-edits` : ''), this.storageService); this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState; this._register(this.chatAgentService.onDidChangeAgents(() => { this.isInitialized = true; - if (this.chatAgentService.getDefaultAgent(ChatAgentLocation.Panel)) { + if (this.chatAgentService.getDefaultAgent(this.chatOptions?.location)) { if (!this._widget?.viewModel) { const sessionId = this.getSessionId(); const model = sessionId ? this.chatService.getOrRestoreSession(sessionId) : undefined; @@ -109,7 +111,7 @@ export class ChatViewPane extends ViewPane { model = model ?? (this.chatService.transferredSessionData?.sessionId ? this.chatService.getOrRestoreSession(this.chatService.transferredSessionData.sessionId) - : this.chatService.startSession(ChatAgentLocation.Panel, CancellationToken.None)); + : this.chatService.startSession(this.chatOptions.location, CancellationToken.None)); if (!model) { throw new Error('Could not start chat session'); } @@ -123,7 +125,7 @@ export class ChatViewPane extends ViewPane { } override shouldShowWelcome(): boolean { - if (!this.chatAgentService.getContributedDefaultAgent(ChatAgentLocation.Panel)) { + if (!this.chatAgentService.getContributedDefaultAgent(this.chatOptions.location)) { return true; } @@ -150,9 +152,9 @@ export class ChatViewPane extends ViewPane { const locationBasedColors = this.getLocationBasedColors(); this._widget = this._register(scopedInstantiationService.createInstance( ChatWidget, - ChatAgentLocation.Panel, + this.chatOptions.location, { viewId: this.id }, - { supportsFileReferences: true }, + { supportsFileReferences: true, supportsAdditionalParticipants: this.chatOptions.location === ChatAgentLocation.Panel }, { listForeground: SIDE_BAR_FOREGROUND, listBackground: locationBasedColors.background, diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 3c3a79cf03fb5..3de9f7c3bf16e 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -32,7 +32,7 @@ import { IThemeService } from '../../../../platform/theme/common/themeService.js import { TerminalChatController } from '../../terminal/terminalContribExports.js'; import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentService, IChatWelcomeMessageContent, isChatWelcomeMessageContent } from '../common/chatAgents.js'; import { CONTEXT_CHAT_INPUT_HAS_AGENT, CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION, CONTEXT_IN_QUICK_CHAT, CONTEXT_LAST_ITEM_ID, CONTEXT_PARTICIPANT_SUPPORTS_MODEL_PICKER, CONTEXT_RESPONSE_FILTERED } from '../common/chatContextKeys.js'; -import { IChatEditingService, IChatEditingSession } from '../common/chatEditingService.js'; +import { ChatEditingSessionState, IChatEditingService, IChatEditingSession } from '../common/chatEditingService.js'; import { IChatModel, IChatRequestVariableEntry, IChatResponseModel } from '../common/chatModel.js'; import { ChatRequestAgentPart, IParsedChatRequest, chatAgentLeader, chatSubcommandLeader, formatChatQuestion } from '../common/chatParserTypes.js'; import { ChatRequestParser } from '../common/chatRequestParser.js'; @@ -271,6 +271,25 @@ export class ChatWidget extends Disposable implements IChatWidget { this.renderChatEditingSessionState(session); })); + if (this._location.location === ChatAgentLocation.EditingSession) { + let currentEditSession: IChatEditingSession | undefined = undefined; + this._register(this.onDidChangeViewModel(async () => { + + const sessionId = this._viewModel?.sessionId; + if (sessionId !== currentEditSession?.chatSessionId) { + if (currentEditSession && (currentEditSession.state.get() !== ChatEditingSessionState.Disposed)) { + await currentEditSession.stop(); + } + if (sessionId) { + currentEditSession = await this.chatEditingService.startOrContinueEditingSession(sessionId, { silent: true }); + } else { + currentEditSession = undefined; + } + } + + })); + } + this._register(codeEditorService.registerCodeEditorOpenHandler(async (input: ITextResourceEditorInput, _source: ICodeEditor | null, _sideBySide?: boolean): Promise => { const resource = input.resource; if (resource.scheme !== Schemas.vscodeChatCodeBlock) { @@ -327,7 +346,7 @@ export class ChatWidget extends Disposable implements IChatWidget { return null; })); - const loadedWelcomeContent = storageService.getObject(PersistWelcomeMessageContentKey, StorageScope.APPLICATION); + const loadedWelcomeContent = storageService.getObject(`${PersistWelcomeMessageContentKey}.${this.location}`, StorageScope.APPLICATION); if (isChatWelcomeMessageContent(loadedWelcomeContent)) { this.persistedWelcomeMessage = loadedWelcomeContent; } @@ -512,7 +531,9 @@ export class ChatWidget extends Disposable implements IChatWidget { const messageResult = this._register(renderer.render(welcomeContent.message)); dom.append(message, messageResult.element); - const tipsString = new MarkdownString(localize('chatWidget.tips', "{0} to attach context\n\n{1} to chat with extensions", '$(attach)', '$(mention)'), { supportThemeIcons: true }); + const tipsString = this.viewOptions.supportsAdditionalParticipants + ? new MarkdownString(localize('chatWidget.tips', "{0} to attach context\n\n{1} to chat with extensions", '$(attach)', '$(mention)'), { supportThemeIcons: true }) + : new MarkdownString(localize('chatWidget.tips.withoutParticipants', "{0} to attach context", '$(attach)'), { supportThemeIcons: true }); const tipsResult = this._register(renderer.render(tipsString)); tips.appendChild(tipsResult.element); } @@ -963,7 +984,7 @@ export class ChatWidget extends Disposable implements IChatWidget { this.tree.getHTMLElement().style.height = `${listHeight}px`; // Push the welcome message down so it doesn't change position when followups appear - const followupsOffset = 100 - this.inputPart.followupsHeight; + const followupsOffset = Math.max(100 - this.inputPart.followupsHeight, 0); this.welcomeMessageContainer.style.height = `${listHeight - followupsOffset}px`; this.welcomeMessageContainer.style.paddingBottom = `${followupsOffset}px`; this.renderer.layout(width); @@ -1116,6 +1137,10 @@ export class ChatWidgetService implements IChatWidgetService { return this._widgets.find(w => isEqual(w.inputUri, uri)); } + getWidgetByLocation(location: ChatAgentLocation): ChatWidget[] { + return this._widgets.filter(w => w.location === location); + } + getWidgetBySessionId(sessionId: string): ChatWidget | undefined { return this._widgets.find(w => w.viewModel?.sessionId === sessionId); } diff --git a/src/vs/workbench/contrib/chat/browser/media/chatInlineAnchorWidget.css b/src/vs/workbench/contrib/chat/browser/media/chatInlineAnchorWidget.css index 751bbdf6350f0..fc672aae75fbc 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatInlineAnchorWidget.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatInlineAnchorWidget.css @@ -9,6 +9,15 @@ margin: 0 1px; padding: 1px 3px; text-wrap: nowrap; + width: fit-content; +} + +.chat-inline-anchor-widget .icon-label { + padding-right: 3px; +} + +.chat-inline-anchor-widget .clickable { + cursor: pointer; } .interactive-item-container .value .rendered-markdown .chat-inline-anchor-widget { diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index 8d3b736c13042..f61c6f1ba4a87 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -23,7 +23,7 @@ import { ILogService } from '../../../../platform/log/common/log.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; import { asJson, IRequestService } from '../../../../platform/request/common/request.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; -import { CONTEXT_CHAT_ENABLED, CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED } from './chatContextKeys.js'; +import { CONTEXT_CHAT_EDITING_PARTICIPANT_REGISTERED, CONTEXT_CHAT_ENABLED, CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED } from './chatContextKeys.js'; import { IChatProgressHistoryResponseContent, IChatRequestVariableData, ISerializableChatAgentData } from './chatModel.js'; import { IRawChatCommandContribution, RawChatParticipantLocation } from './chatParticipantContribTypes.js'; import { IChatFollowup, IChatLocationData, IChatProgress, IChatResponseErrorDetails, IChatTaskDto } from './chatService.js'; @@ -40,7 +40,8 @@ export enum ChatAgentLocation { Panel = 'panel', Terminal = 'terminal', Notebook = 'notebook', - Editor = 'editor' + Editor = 'editor', + EditingSession = 'editing-session', } export namespace ChatAgentLocation { @@ -50,6 +51,7 @@ export namespace ChatAgentLocation { case 'terminal': return ChatAgentLocation.Terminal; case 'notebook': return ChatAgentLocation.Notebook; case 'editor': return ChatAgentLocation.Editor; + case 'editing-session': return ChatAgentLocation.EditingSession; } return ChatAgentLocation.Panel; } @@ -248,12 +250,14 @@ export class ChatAgentService implements IChatAgentService { private readonly _hasDefaultAgent: IContextKey; private readonly _defaultAgentRegistered: IContextKey; + private readonly _editingAgentRegistered: IContextKey; constructor( @IContextKeyService private readonly contextKeyService: IContextKeyService, ) { this._hasDefaultAgent = CONTEXT_CHAT_ENABLED.bindTo(this.contextKeyService); this._defaultAgentRegistered = CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED.bindTo(this.contextKeyService); + this._editingAgentRegistered = CONTEXT_CHAT_EDITING_PARTICIPANT_REGISTERED.bindTo(this.contextKeyService); } registerAgent(id: string, data: IChatAgentData): IDisposable { @@ -262,7 +266,9 @@ export class ChatAgentService implements IChatAgentService { throw new Error(`Agent already registered: ${JSON.stringify(id)}`); } - if (data.isDefault) { + if (data.isDefault && data.locations.includes(ChatAgentLocation.EditingSession)) { + this._editingAgentRegistered.set(true); + } else if (data.isDefault) { this._defaultAgentRegistered.set(true); } @@ -279,7 +285,9 @@ export class ChatAgentService implements IChatAgentService { this._onDidChangeAgents.fire(undefined); return toDisposable(() => { this._agents.delete(id); - if (data.isDefault) { + if (data.isDefault && data.locations.includes(ChatAgentLocation.EditingSession)) { + this._editingAgentRegistered.set(false); + } else if (data.isDefault) { this._defaultAgentRegistered.set(false); } diff --git a/src/vs/workbench/contrib/chat/common/chatCodeMapperService.ts b/src/vs/workbench/contrib/chat/common/chatCodeMapperService.ts index e64fea9e5db0b..bb6b812551f85 100644 --- a/src/vs/workbench/contrib/chat/common/chatCodeMapperService.ts +++ b/src/vs/workbench/contrib/chat/common/chatCodeMapperService.ts @@ -4,10 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken } from '../../../../base/common/cancellation.js'; +import { CharCode } from '../../../../base/common/charCode.js'; import { IDisposable } from '../../../../base/common/lifecycle.js'; +import { ResourceMap } from '../../../../base/common/map.js'; +import { splitLinesIncludeSeparators } from '../../../../base/common/strings.js'; +import { isString } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; -import { TextEdit } from '../../../../editor/common/languages.js'; +import { DocumentContextItem, isLocation, TextEdit } from '../../../../editor/common/languages.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; +import { IChatAgentResult } from './chatAgents.js'; +import { IChatResponseModel } from './chatModel.js'; +import { IChatContentReference } from './chatService.js'; export interface ICodeMapperResponse { @@ -15,8 +22,9 @@ export interface ICodeMapperResponse { } export interface ICodeMapperCodeBlock { - code: string; - resource: URI; + readonly code: string; + readonly resource: URI; + readonly markdownBeforeBlock?: string; } export interface ConversationRequest { @@ -27,16 +35,17 @@ export interface ConversationRequest { export interface ConversationResponse { readonly type: 'response'; readonly message: string; - // readonly references?: DocumentContextItem[]; + readonly result?: IChatAgentResult; + readonly references?: DocumentContextItem[]; } export interface ICodeMapperRequest { - codeBlocks: ICodeMapperCodeBlock[]; - conversation: (ConversationRequest | ConversationResponse)[]; + readonly codeBlocks: ICodeMapperCodeBlock[]; + readonly conversation: (ConversationResponse | ConversationRequest)[]; } export interface ICodeMapperResult { - errorMessage?: string; + readonly errorMessage?: string; } export interface ICodeMapperProvider { @@ -49,6 +58,7 @@ export interface ICodeMapperService { readonly _serviceBrand: undefined; registerCodeMapperProvider(handle: number, provider: ICodeMapperProvider): IDisposable; mapCode(request: ICodeMapperRequest, response: ICodeMapperResponse, token: CancellationToken): Promise; + mapCodeFromResponse(responseModel: IChatResponseModel, response: ICodeMapperResponse, token: CancellationToken): Promise; } export class CodeMapperService implements ICodeMapperService { @@ -77,4 +87,119 @@ export class CodeMapperService implements ICodeMapperService { } return undefined; } + + async mapCodeFromResponse(responseModel: IChatResponseModel, response: ICodeMapperResponse, token: CancellationToken) { + const fenceLanguageRegex = /^`{3,}/; + const codeBlocks: ICodeMapperCodeBlock[] = []; + + const currentBlock = []; + const markdownBeforeBlock = []; + let currentBlockUri = undefined; + + let fence = undefined; // if set, we are in a block + + for (const lineOrUri of iterateLinesOrUris(responseModel)) { + if (isString(lineOrUri)) { + const fenceLanguageIdMatch = lineOrUri.match(fenceLanguageRegex); + if (fenceLanguageIdMatch) { + // we found a line that starts with a fence + if (fence !== undefined && fenceLanguageIdMatch[0] === fence) { + // we are in a code block and the fence matches the opening fence: Close the code block + fence = undefined; + if (currentBlockUri) { + // report the code block if we have a URI + codeBlocks.push({ code: currentBlock.join(''), resource: currentBlockUri, markdownBeforeBlock: markdownBeforeBlock.join('') }); + currentBlock.length = 0; + markdownBeforeBlock.length = 0; + currentBlockUri = undefined; + } + } else { + // we are not in a code block. Open the block + fence = fenceLanguageIdMatch[0]; + } + } else { + if (fence !== undefined) { + currentBlock.push(lineOrUri); + } else { + markdownBeforeBlock.push(lineOrUri); + } + } + } else { + currentBlockUri = lineOrUri; + } + } + const conversation: (ConversationRequest | ConversationResponse)[] = []; + for (const request of responseModel.session.getRequests()) { + const response = request.response; + if (!response || response === responseModel) { + break; + } + conversation.push({ + type: 'request', + message: request.message.text + }); + conversation.push({ + type: 'response', + message: response.response.toMarkdown(), + result: response.result, + references: getReferencesAsDocumentContext(response.contentReferences) + }); + } + return this.mapCode({ codeBlocks, conversation }, response, token); + } +} + +function iterateLinesOrUris(responseModel: IChatResponseModel): Iterable { + return { + *[Symbol.iterator](): Iterator { + let lastIncompleteLine = undefined; + for (const part of responseModel.response.value) { + if (part.kind === 'markdownContent' || part.kind === 'markdownVuln') { + const lines = splitLinesIncludeSeparators(part.content.value); + if (lines.length > 0) { + if (lastIncompleteLine !== undefined) { + lines[0] = lastIncompleteLine + lines[0]; // merge the last incomplete line with the first markdown line + } + lastIncompleteLine = isLineIncomplete(lines[lines.length - 1]) ? lines.pop() : undefined; + for (const line of lines) { + yield line; + } + } + } else if (part.kind === 'codeblockUri') { + yield part.uri; + } + } + } + }; +} + +function isLineIncomplete(line: string) { + const lastChar = line.charCodeAt(line.length - 1); + return lastChar !== CharCode.LineFeed && lastChar !== CharCode.CarriageReturn; +} + + +export function getReferencesAsDocumentContext(res: readonly IChatContentReference[]): DocumentContextItem[] { + const map = new ResourceMap(); + for (const r of res) { + let uri; + let range; + if (URI.isUri(r.reference)) { + uri = r.reference; + } else if (isLocation(r.reference)) { + uri = r.reference.uri; + range = r.reference.range; + } + if (uri) { + const item = map.get(uri); + if (item) { + if (range) { + item.ranges.push(range); + } + } else { + map.set(uri, { uri, version: -1, ranges: range ? [range] : [] }); + } + } + } + return [...map.values()]; } diff --git a/src/vs/workbench/contrib/chat/common/chatContextKeys.ts b/src/vs/workbench/contrib/chat/common/chatContextKeys.ts index 7ab7d0affe425..5c283f4f7ef67 100644 --- a/src/vs/workbench/contrib/chat/common/chatContextKeys.ts +++ b/src/vs/workbench/contrib/chat/common/chatContextKeys.ts @@ -28,6 +28,7 @@ export const CONTEXT_IN_CHAT_SESSION = new RawContextKey('inChat', fals export const CONTEXT_CHAT_ENABLED = new RawContextKey('chatIsEnabled', false, { type: 'boolean', description: localize('chatIsEnabled', "True when chat is enabled because a default chat participant is activated with an implementation.") }); export const CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED = new RawContextKey('chatPanelParticipantRegistered', false, { type: 'boolean', description: localize('chatParticipantRegistered', "True when a default chat participant is registered for the panel.") }); +export const CONTEXT_CHAT_EDITING_PARTICIPANT_REGISTERED = new RawContextKey('chatEditingParticipantRegistered', false, { type: 'boolean', description: localize('chatEditingParticipantRegistered', "True when a default chat participant is registered for editing.") }); export const CONTEXT_CHAT_EXTENSION_INVALID = new RawContextKey('chatExtensionInvalid', false, { type: 'boolean', description: localize('chatExtensionInvalid', "True when the installed chat extension is invalid and needs to be updated.") }); export const CONTEXT_CHAT_INPUT_CURSOR_AT_TOP = new RawContextKey('chatCursorAtTop', false); export const CONTEXT_CHAT_INPUT_HAS_AGENT = new RawContextKey('chatInputHasAgent', false); diff --git a/src/vs/workbench/contrib/chat/common/chatEditingService.ts b/src/vs/workbench/contrib/chat/common/chatEditingService.ts index 85df0983324ac..0454b567511f9 100644 --- a/src/vs/workbench/contrib/chat/common/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/common/chatEditingService.ts @@ -8,6 +8,7 @@ import { IObservable, ITransaction } from '../../../../base/common/observable.js import { URI } from '../../../../base/common/uri.js'; import { TextEdit } from '../../../../editor/common/languages.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; +import { IChatResponseModel } from './chatModel.js'; export const IChatEditingService = createDecorator('chatEditingService'); @@ -18,7 +19,8 @@ export interface IChatEditingService { readonly currentEditingSession: IChatEditingSession | null; - startOrContinueEditingSession(chatSessionId: string, builder?: (stream: IChatEditingSessionStream) => Promise, options?: { silent?: boolean }): Promise; + startOrContinueEditingSession(chatSessionId: string, options?: { silent: boolean }): Promise; + triggerEditComputation(responseModel: IChatResponseModel): Promise; } export interface IChatEditingSession { diff --git a/src/vs/workbench/contrib/chat/common/chatParticipantContribTypes.ts b/src/vs/workbench/contrib/chat/common/chatParticipantContribTypes.ts index b123b654ced6f..c2eea41c05c06 100644 --- a/src/vs/workbench/contrib/chat/common/chatParticipantContribTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParticipantContribTypes.ts @@ -13,7 +13,7 @@ export interface IRawChatCommandContribution { disambiguation?: { category: string; categoryName?: string /** Deprecated */; description: string; examples: string[] }[]; } -export type RawChatParticipantLocation = 'panel' | 'terminal' | 'notebook'; +export type RawChatParticipantLocation = 'panel' | 'terminal' | 'notebook' | 'editing-session'; export interface IRawChatParticipantContribution { id: string; diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts index 636fd55a28487..b700d50644af4 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts @@ -599,7 +599,7 @@ export class StartVoiceChatAction extends Action2 { menu: [ { id: MenuId.ChatInput, - when: ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Panel), menuCondition), + when: ContextKeyExpr.and(ContextKeyExpr.or(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Panel), CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession)), menuCondition), group: 'navigation', order: 3 }, diff --git a/src/vs/workbench/contrib/chat/test/browser/mockChatWidget.ts b/src/vs/workbench/contrib/chat/test/browser/mockChatWidget.ts index c5e26d45f3ec5..8bf8cbebd77fc 100644 --- a/src/vs/workbench/contrib/chat/test/browser/mockChatWidget.ts +++ b/src/vs/workbench/contrib/chat/test/browser/mockChatWidget.ts @@ -5,6 +5,7 @@ import { URI } from '../../../../../base/common/uri.js'; import { IChatWidget, IChatWidgetService } from '../../browser/chat.js'; +import { ChatAgentLocation } from '../../common/chatAgents.js'; export class MockChatWidgetService implements IChatWidgetService { readonly _serviceBrand: undefined; @@ -21,4 +22,8 @@ export class MockChatWidgetService implements IChatWidgetService { getWidgetBySessionId(sessionId: string): IChatWidget | undefined { return undefined; } + + getWidgetByLocation(location: ChatAgentLocation): IChatWidget[] { + return []; + } } diff --git a/src/vs/workbench/contrib/debug/browser/debugExpressionRenderer.ts b/src/vs/workbench/contrib/debug/browser/debugExpressionRenderer.ts index 7b52198a7bd48..324a0669579d8 100644 --- a/src/vs/workbench/contrib/debug/browser/debugExpressionRenderer.ts +++ b/src/vs/workbench/contrib/debug/browser/debugExpressionRenderer.ts @@ -49,6 +49,26 @@ const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024; const booleanRegex = /^(true|false)$/i; const stringRegex = /^(['"]).*\1$/; +const enum Cls { + Value = 'value', + Unavailable = 'unavailable', + Error = 'error', + Changed = 'changed', + Boolean = 'boolean', + String = 'string', + Number = 'number', +} + +const allClasses: readonly Cls[] = Object.keys({ + [Cls.Value]: 0, + [Cls.Unavailable]: 0, + [Cls.Error]: 0, + [Cls.Changed]: 0, + [Cls.Boolean]: 0, + [Cls.String]: 0, + [Cls.Number]: 0, +} satisfies { [key in Cls]: unknown }) as Cls[]; + export class DebugExpressionRenderer { private displayType: IObservable; private readonly linkDetector: LinkDetector; @@ -110,17 +130,20 @@ export class DebugExpressionRenderer { let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value; // remove stale classes - container.className = 'value'; + for (const cls of allClasses) { + container.classList.remove(cls); + } + container.classList.add(Cls.Value); // when resolving expressions we represent errors from the server as a variable with name === null. if (value === null || ((expressionOrValue instanceof Expression || expressionOrValue instanceof Variable || expressionOrValue instanceof ReplEvaluationResult) && !expressionOrValue.available)) { - container.classList.add('unavailable'); + container.classList.add(Cls.Unavailable); if (value !== Expression.DEFAULT_VALUE) { - container.classList.add('error'); + container.classList.add(Cls.Error); } } else { if (typeof expressionOrValue !== 'string' && options.showChanged && expressionOrValue.valueChanged && value !== Expression.DEFAULT_VALUE) { // value changed color has priority over other colors. - container.className = 'value changed'; + container.classList.add(Cls.Changed); expressionOrValue.valueChanged = false; } @@ -128,11 +151,11 @@ export class DebugExpressionRenderer { if (expressionOrValue.type === 'number' || expressionOrValue.type === 'boolean' || expressionOrValue.type === 'string') { container.classList.add(expressionOrValue.type); } else if (!isNaN(+value)) { - container.classList.add('number'); + container.classList.add(Cls.Number); } else if (booleanRegex.test(value)) { - container.classList.add('boolean'); + container.classList.add(Cls.Boolean); } else if (stringRegex.test(value)) { - container.classList.add('string'); + container.classList.add(Cls.String); } } } diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index 0a381676af000..5b49fbe87e425 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -321,8 +321,7 @@ export class DebugHoverWidget implements IContentWidget { this.valueContainer.hidden = true; this.expressionToRender = expression; - this.complexValueTitle.textContent = expression.value; - this.complexValueTitle.title = expression.value; + store.add(this.expressionRenderer.renderValue(this.complexValueTitle, expression, { hover: false, session })); this.editor.layoutContentWidget(this); this.tree.scrollTop = 0; this.tree.scrollLeft = 0; diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 7e33db78057e0..613fed3ce95ba 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -210,6 +210,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget { this.refreshReplElements(true); if (this.styleChangedWhenInvisible) { this.styleChangedWhenInvisible = false; + this.tree?.updateChildren(undefined, true, false); this.onDidStyleChange(); } } diff --git a/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts index 7c66831722b4b..fcefad3c51672 100644 --- a/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts @@ -116,26 +116,26 @@ suite('Debug - Base Debug View', () => { let container = $('.container'); const store = disposables.add(new DisposableStore()); store.add(renderer.renderValue(container, 'render \n me', {})); - assert.strictEqual(container.className, 'value'); + assert.strictEqual(container.className, 'container value'); assert.strictEqual(container.textContent, 'render \n me'); const expression = new Expression('console'); expression.value = 'Object'; container = $('.container'); store.add(renderer.renderValue(container, expression, { colorize: true })); - assert.strictEqual(container.className, 'value unavailable error'); + assert.strictEqual(container.className, 'container value unavailable error'); expression.available = true; expression.value = '"string value"'; container = $('.container'); store.add(renderer.renderValue(container, expression, { colorize: true })); - assert.strictEqual(container.className, 'value string'); + assert.strictEqual(container.className, 'container value string'); assert.strictEqual(container.textContent, '"string value"'); expression.type = 'boolean'; container = $('.container'); store.add(renderer.renderValue(container, expression, { colorize: true })); - assert.strictEqual(container.className, 'value boolean'); + assert.strictEqual(container.className, 'container value boolean'); assert.strictEqual(container.textContent, expression.value); expression.value = 'this is a long string'; diff --git a/src/vs/workbench/contrib/encryption/electron-sandbox/encryption.contribution.ts b/src/vs/workbench/contrib/encryption/electron-sandbox/encryption.contribution.ts index c6061279a7a2e..a530edf2bbf23 100644 --- a/src/vs/workbench/contrib/encryption/electron-sandbox/encryption.contribution.ts +++ b/src/vs/workbench/contrib/encryption/electron-sandbox/encryption.contribution.ts @@ -34,7 +34,7 @@ class EncryptionContribution implements IWorkbenchContribution { } try { const content = await this.fileService.readFile(this.environmentService.argvResource); - const argv = parse(content.value.toString()); + const argv = parse<{ 'password-store'?: string }>(content.value.toString()); if (argv['password-store'] === 'gnome' || argv['password-store'] === 'gnome-keyring') { this.jsonEditingService.write(this.environmentService.argvResource, [{ path: ['password-store'], value: 'gnome-libsecret' }], true); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 1b0716f2670f6..3930f44a866f0 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -164,7 +164,7 @@ export class PromptExtensionInstallFailureAction extends Action { detail: getErrorMessage(this.error), buttons: [{ label: localize('learn more', "Learn More"), - run: () => this.openerService.open('https://code.visualstudio.com/docs/editor/extension-marketplace') + run: () => this.openerService.open('https://code.visualstudio.com/docs/editor/extension-marketplace#_the-extension-signature-cannot-be-verified-by-vs-code') }, { label: localize('install donot verify', "Install Anyway (Don't Verify Signature)"), run: () => { diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 81904a45cec17..ec2a3a69d0aaa 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -767,6 +767,36 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { }); +// Chat used attachment anchor context menu + +MenuRegistry.appendMenuItem(MenuId.ChatAttachmentsContext, { + group: 'navigation', + order: 10, + command: openToSideCommand, + when: ContextKeyExpr.and(ResourceContextKey.HasResource, ExplorerFolderContext.toNegated()) +}); + +MenuRegistry.appendMenuItem(MenuId.ChatAttachmentsContext, { + group: 'navigation', + order: 20, + command: revealInsideBarCommand, + when: ResourceContextKey.IsFileSystemResource +}); + +MenuRegistry.appendMenuItem(MenuId.ChatAttachmentsContext, { + group: '1_cutcopypaste', + order: 10, + command: copyPathCommand, + when: ResourceContextKey.IsFileSystemResource +}); + +MenuRegistry.appendMenuItem(MenuId.ChatAttachmentsContext, { + group: '1_cutcopypaste', + order: 20, + command: copyRelativePathCommand, + when: ResourceContextKey.IsFileSystemResource +}); + // Chat resource anchor context menu MenuRegistry.appendMenuItem(MenuId.ChatInlineResourceAnchorContext, { diff --git a/src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts b/src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts index 1d75d5e5e44ca..5581931a9e7d1 100644 --- a/src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts @@ -97,6 +97,15 @@ appendToCommandPalette({ category: category }, REVEAL_IN_OS_WHEN_CONTEXT); +// Menu registration - chat attachments context + +MenuRegistry.appendMenuItem(MenuId.ChatAttachmentsContext, { + group: 'navigation', + order: 20, + command: revealInOsCommand, + when: REVEAL_IN_OS_WHEN_CONTEXT +}); + // Menu registration - chat inline anchor MenuRegistry.appendMenuItem(MenuId.ChatInlineResourceAnchorContext, { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts index 70eb1adb07ab6..bf80d6d241b40 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts @@ -92,7 +92,6 @@ registerAction2(InlineChatActions.CloseAction); registerAction2(InlineChatActions.ConfigureInlineChatAction); registerAction2(InlineChatActions.UnstashSessionAction); registerAction2(InlineChatActions.DiscardHunkAction); -registerAction2(InlineChatActions.DiscardAction); registerAction2(InlineChatActions.RerunAction); registerAction2(InlineChatActions.MoveToNextHunk); registerAction2(InlineChatActions.MoveToPreviousHunk); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts index 9dee0206e0e30..9ad93733dcb5f 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts @@ -11,7 +11,7 @@ import { EmbeddedDiffEditorWidget } from '../../../../editor/browser/widget/diff import { EmbeddedCodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/embeddedCodeEditorWidget.js'; import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js'; import { InlineChatController, InlineChatRunOptions } from './inlineChatController.js'; -import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, MENU_INLINE_CHAT_ZONE, ACTION_DISCARD_CHANGES, CTX_INLINE_CHAT_POSSIBLE } from '../common/inlineChat.js'; +import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, MENU_INLINE_CHAT_ZONE, ACTION_DISCARD_CHANGES, CTX_INLINE_CHAT_POSSIBLE } from '../common/inlineChat.js'; import { localize, localize2 } from '../../../../nls.js'; import { Action2, IAction2Options, MenuId } from '../../../../platform/actions/common/actions.js'; import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; @@ -235,27 +235,6 @@ export class FocusInlineChat extends EditorAction2 { } -export class DiscardAction extends AbstractInlineChatAction { - - constructor() { - super({ - id: 'inlineChat.discard', - title: localize('discard', 'Discard'), - icon: Codicon.discard, - precondition: CTX_INLINE_CHAT_VISIBLE, - keybinding: { - weight: KeybindingWeight.EditorContrib - 1, - primary: KeyCode.Escape, - when: CTX_INLINE_CHAT_USER_DID_EDIT.negate() - } - }); - } - - async runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController, _editor: ICodeEditor, ..._args: any[]): Promise { - await ctrl.cancelSession(); - } -} - export class AcceptChanges extends AbstractInlineChatAction { constructor() { @@ -316,7 +295,7 @@ export class DiscardHunkAction extends AbstractInlineChatAction { order: 2 }], keybinding: { - weight: KeybindingWeight.WorkbenchContrib, + weight: KeybindingWeight.EditorContrib, primary: KeyCode.Escape, when: CTX_INLINE_CHAT_RESPONSE_TYPE.isEqualTo(InlineChatResponseType.MessagesAndEdits) } @@ -374,7 +353,7 @@ export class CloseAction extends AbstractInlineChatAction { icon: Codicon.close, precondition: CTX_INLINE_CHAT_VISIBLE, keybinding: { - weight: KeybindingWeight.WorkbenchContrib, + weight: KeybindingWeight.EditorContrib + 1, primary: KeyCode.Escape, }, menu: [{ diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index fdee6a189c116..ca9f2b1117d89 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Dimension, getActiveElement, getTotalHeight, h, reset, trackFocus } from '../../../../base/browser/dom.js'; +import { $, Dimension, getActiveElement, getTotalHeight, h, reset, trackFocus } from '../../../../base/browser/dom.js'; import { IActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js'; import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js'; import { renderLabelWithIcons } from '../../../../base/browser/ui/iconLabel/iconLabels.js'; @@ -54,6 +54,7 @@ import { isResponseVM } from '../../chat/common/chatViewModel.js'; import { HunkInformation, Session } from './inlineChatSession.js'; import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_RESPONSE_FOCUSED, inlineChatBackground, inlineChatForeground } from '../common/inlineChat.js'; import { EDITOR_DRAG_AND_DROP_BACKGROUND } from '../../../common/theme.js'; +import { ILayoutService } from '../../../../platform/layout/browser/layoutService.js'; export interface InlineChatWidgetViewState { @@ -570,6 +571,7 @@ export class EditorBasedInlineChatWidget extends InlineChatWidget { private readonly _accessibleViewer = this._store.add(new MutableDisposable()); + constructor( location: IChatWidgetLocationOptions, private readonly _parentEditor: ICodeEditor, @@ -583,12 +585,13 @@ export class EditorBasedInlineChatWidget extends InlineChatWidget { @ITextModelService textModelResolverService: ITextModelService, @IChatService chatService: IChatService, @IHoverService hoverService: IHoverService, + @ILayoutService layoutService: ILayoutService ) { super(location, { ...options, chatWidgetViewOptions: { ...options.chatWidgetViewOptions, - // editorOverflowWidgetsDomNode: _parentEditor.getOverflowWidgetsDomNode() ?? _parentEditor.getDomNode() ?? undefined + editorOverflowWidgetsDomNode: layoutService.mainContainer.appendChild($('.inline-chat-overflow.monaco-editor')) } }, instantiationService, contextKeyService, keybindingService, accessibilityService, configurationService, accessibleViewService, textModelResolverService, chatService, hoverService); } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts index 8740c9b09df26..5e732d8a83a9b 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts @@ -168,7 +168,9 @@ export class InlineChatZoneWidget extends ZoneWidget { } reveal(position: Position) { - this.editor.revealLinesInCenterIfOutsideViewport(position.lineNumber, position.lineNumber, ScrollType.Immediate); + const stickyScroll = this.editor.getOption(EditorOption.stickyScroll); + const magicValue = stickyScroll.enabled ? stickyScroll.maxLineCount : 0; + this.editor.revealLines(position.lineNumber + magicValue, position.lineNumber + magicValue, ScrollType.Immediate); this._scrollUp.reset(); this.updatePositionAndHeight(position); } diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.esm.html b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.esm.html deleted file mode 100644 index f14661a283ce6..0000000000000 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.esm.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.html b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.html index 9d853e358a06a..f14661a283ce6 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.html +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.html @@ -15,6 +15,8 @@ ; script-src 'self' + blob: + 'nonce-0c6a828f1297' ; style-src 'self' @@ -39,7 +41,6 @@ - diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.esm.html b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.esm.html deleted file mode 100644 index 2f87d2489cef9..0000000000000 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.esm.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.html b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.html index 8d0bcc6c87c0c..2f87d2489cef9 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.html +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.html @@ -15,6 +15,8 @@ ; script-src 'self' + blob: + 'nonce-0c6a828f1297' ; style-src 'self' @@ -39,5 +41,5 @@ - + diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.js b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.js deleted file mode 100644 index 15a7f2a211ddf..0000000000000 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.js +++ /dev/null @@ -1,50 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -(function () { - - /** - * @import { ISandboxConfiguration } from '../../../../base/parts/sandbox/common/sandboxTypes' - */ - - const bootstrapWindow = bootstrapWindowLib(); - - // Load issue reporter into window - bootstrapWindow.load(['vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'], function (issueReporter, configuration) { - return issueReporter.startup(configuration); - }, - { - configureDeveloperSettings: function () { - return { - forceEnableDeveloperKeybindings: true, - disallowReloadKeybinding: true - }; - } - } - ); - - /** - * @returns {{ - * load: ( - * modules: string[], - * resultCallback: (result: any, configuration: ISandboxConfiguration) => unknown, - * options?: { - * configureDeveloperSettings?: (config: ISandboxConfiguration) => { - * forceEnableDeveloperKeybindings?: boolean, - * disallowReloadKeybinding?: boolean, - * removeDeveloperKeybindingsAfterLoad?: boolean - * } - * } - * ) => Promise - * }} - */ - function bootstrapWindowLib() { - // @ts-ignore (defined in bootstrap-window.js) - return window.MonacoBootstrapWindow; - } -}()); diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.ts new file mode 100644 index 0000000000000..3aeee60b74a27 --- /dev/null +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/* eslint-disable no-restricted-globals */ + +(function () { + + type IBootstrapWindow = import('vs/platform/window/electron-sandbox/window.js').IBootstrapWindow; + const bootstrapWindow: IBootstrapWindow = (window as any).MonacoBootstrapWindow; // defined by bootstrap-window.ts + + bootstrapWindow.load('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain', function (issueReporter, configuration) { + return issueReporter.startup(configuration); + }, { + configureDeveloperSettings: function () { + return { + forceEnableDeveloperKeybindings: true, + disallowReloadKeybinding: true + }; + } + }); +}()); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts index 154a29b9173ee..dd7de68ed52be 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts @@ -33,6 +33,7 @@ import { IAccessibilityService } from '../../../../../platform/accessibility/com import { localize } from '../../../../../nls.js'; import { IEditorConstructionOptions } from '../../../../../editor/browser/config/editorConfiguration.js'; import { IDiffEditorConstructionOptions } from '../../../../../editor/browser/editorBrowser.js'; +import { EditorExtensionsRegistry } from '../../../../../editor/browser/editorExtensions.js'; export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate { private readonly lineHeight: number; @@ -607,7 +608,9 @@ function buildDiffEditorWidget(instantiationService: IInstantiationService, note function buildSourceEditor(instantiationService: IInstantiationService, notebookEditor: INotebookTextDiffEditor, sourceContainer: HTMLElement, options: IEditorConstructionOptions = {}) { const editorContainer = DOM.append(sourceContainer, DOM.$('.editor-container')); - + const skipContributions = [ + 'editor.contrib.emptyTextEditorHint' + ]; const editor = instantiationService.createInstance(CodeEditorWidget, editorContainer, { ...fixedEditorOptions, glyphMargin: false, @@ -618,7 +621,9 @@ function buildSourceEditor(instantiationService: IInstantiationService, notebook automaticLayout: false, overflowWidgetsDomNode: notebookEditor.getOverflowContainerDomNode(), readOnly: true, - }, {}); + }, { + contributions: EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1) + }); return { editor, editorContainer }; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index fb9e830392149..8eb293b41bac3 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -569,7 +569,7 @@ export class BackLayerWebView extends Themable { } return [ - dirname(FileAccess.asFileUri('vs/loader.js')), // TODO@esm this file will not exist in the future + dirname(FileAccess.asFileUri('vs/nls.js')), ]; } diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index 951dd65141b9e..37559fe0aa3ee 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -17,7 +17,6 @@ import { IExtensionService } from '../../../services/extensions/common/extension import { IDisposable, dispose } from '../../../../base/common/lifecycle.js'; import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; import { writeTransientState } from '../../codeEditor/browser/toggleWordWrap.js'; -import { LoaderEventType, LoaderStats, isESM } from '../../../../base/common/amd.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; import { ITextFileService } from '../../../services/textfile/common/textfiles.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; @@ -31,6 +30,7 @@ import { ITextResourceConfigurationService } from '../../../../editor/common/ser import { Registry } from '../../../../platform/registry/common/platform.js'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, getWorkbenchContribution } from '../../../common/contributions.js'; import { ICustomEditorLabelService } from '../../../services/editor/common/customEditorLabelService.js'; +import { IRemoteAgentService } from '../../../services/remote/common/remoteAgentService.js'; export class PerfviewContrib { @@ -112,6 +112,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { @ITimerService private readonly _timerService: ITimerService, @IExtensionService private readonly _extensionService: IExtensionService, @IProductService private readonly _productService: IProductService, + @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService, @ITerminalService private readonly _terminalService: ITerminalService ) { } @@ -139,15 +140,15 @@ class PerfModelContentProvider implements ITextModelContentProvider { this._timerService.whenReady(), this._lifecycleService.when(LifecyclePhase.Eventually), this._extensionService.whenInstalledExtensionsRegistered(), - this._terminalService.whenConnected + // The terminal service never connects to the pty host on the web + isWeb && !this._remoteAgentService.getConnection()?.remoteAuthority ? Promise.resolve() : this._terminalService.whenConnected ]).then(() => { if (this._model && !this._model.isDisposed()) { - const stats = LoaderStats.get(); const md = new MarkdownBuilder(); this._addSummary(md); md.blank(); - this._addSummaryTable(md, stats); + this._addSummaryTable(md); md.blank(); this._addExtensionsTable(md); md.blank(); @@ -156,12 +157,6 @@ class PerfModelContentProvider implements ITextModelContentProvider { this._addWorkbenchContributionsPerfMarksTable(md); md.blank(); this._addRawPerfMarks(md); - if (!isESM) { - md.blank(); - this._addLoaderStats(md, stats); - md.blank(); - this._addCachedDataStats(md); - } md.blank(); this._addResourceTimingStats(md); @@ -192,7 +187,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { md.li(`Empty Workspace: ${metrics.emptyWorkbench}`); } - private _addSummaryTable(md: MarkdownBuilder, stats?: LoaderStats): void { + private _addSummaryTable(md: MarkdownBuilder): void { const metrics = this._timerService.startupMetrics; const contribTimings = Registry.as(WorkbenchExtensions.Workbench).timings; @@ -206,7 +201,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { table.push(['create window', metrics.timers.ellapsedWindowCreate, '[main]', `initial startup: ${metrics.initialStartup}, ${metrics.initialStartup ? `state: ${metrics.timers.ellapsedWindowRestoreState}ms, widget: ${metrics.timers.ellapsedBrowserWindowCreate}ms, show: ${metrics.timers.ellapsedWindowMaximize}ms` : ''}`]); table.push(['app.isReady => window.loadUrl()', metrics.timers.ellapsedWindowLoad, '[main]', `initial startup: ${metrics.initialStartup}`]); table.push(['window.loadUrl() => begin to import(workbench.desktop.main.js)', metrics.timers.ellapsedWindowLoadToRequire, '[main->renderer]', StartupKindToString(metrics.windowKind)]); - table.push(['import(workbench.desktop.main.js)', metrics.timers.ellapsedRequire, '[renderer]', `cached data: ${(metrics.didUseCachedData ? 'YES' : 'NO')}${stats ? `, node_modules took ${stats.nodeRequireTotal}ms` : ''}`]); + table.push(['import(workbench.desktop.main.js)', metrics.timers.ellapsedRequire, '[renderer]', `cached data: ${(metrics.didUseCachedData ? 'YES' : 'NO')}`]); table.push(['wait for window config', metrics.timers.ellapsedWaitForWindowConfig, '[renderer]', undefined]); table.push(['init storage (global & workspace)', metrics.timers.ellapsedStorageInit, '[renderer]', undefined]); table.push(['init workspace service', metrics.timers.ellapsedWorkspaceServiceInit, '[renderer]', undefined]); @@ -310,58 +305,6 @@ class PerfModelContentProvider implements ITextModelContentProvider { } } - private _addLoaderStats(md: MarkdownBuilder, stats: LoaderStats): void { - md.heading(2, 'Loader Stats'); - md.heading(3, 'Load AMD-module'); - md.table(['Module', 'Duration'], stats.amdLoad); - md.blank(); - md.heading(3, 'Load commonjs-module'); - md.table(['Module', 'Duration'], stats.nodeRequire); - md.blank(); - md.heading(3, 'Invoke AMD-module factory'); - md.table(['Module', 'Duration'], stats.amdInvoke); - md.blank(); - md.heading(3, 'Invoke commonjs-module'); - md.table(['Module', 'Duration'], stats.nodeEval); - } - - private _addCachedDataStats(md: MarkdownBuilder): void { - - const map = new Map(); - map.set(LoaderEventType.CachedDataCreated, []); - map.set(LoaderEventType.CachedDataFound, []); - map.set(LoaderEventType.CachedDataMissed, []); - map.set(LoaderEventType.CachedDataRejected, []); - if (!isESM && typeof require.getStats === 'function') { - for (const stat of require.getStats()) { - if (map.has(stat.type)) { - map.get(stat.type)!.push(stat.detail); - } - } - } - - const printLists = (arr?: string[]) => { - if (arr) { - arr.sort(); - for (const e of arr) { - md.li(`${e}`); - } - md.blank(); - } - }; - - md.heading(2, 'Node Cached Data Stats'); - md.blank(); - md.heading(3, 'cached data used'); - printLists(map.get(LoaderEventType.CachedDataFound)); - md.heading(3, 'cached data missed'); - printLists(map.get(LoaderEventType.CachedDataMissed)); - md.heading(3, 'cached data rejected'); - printLists(map.get(LoaderEventType.CachedDataRejected)); - md.heading(3, 'cached data created (lazy, might need refreshes)'); - printLists(map.get(LoaderEventType.CachedDataCreated)); - } - private _addResourceTimingStats(md: MarkdownBuilder) { const stats = performance.getEntriesByType('resource').map(entry => { return [entry.name, entry.duration]; @@ -394,6 +337,42 @@ class MarkdownBuilder { } table(header: string[], rows: Array>) { - this.value += LoaderStats.toMarkdownTable(header, rows); + this.value += this.toMarkdownTable(header, rows); + } + + private toMarkdownTable(header: string[], rows: Array>): string { + let result = ''; + + const lengths: number[] = []; + header.forEach((cell, ci) => { + lengths[ci] = cell.length; + }); + rows.forEach(row => { + row.forEach((cell, ci) => { + if (typeof cell === 'undefined') { + cell = row[ci] = '-'; + } + const len = cell.toString().length; + lengths[ci] = Math.max(len, lengths[ci]); + }); + }); + + // header + header.forEach((cell, ci) => { result += `| ${cell + ' '.repeat(lengths[ci] - cell.toString().length)} `; }); + result += '|\n'; + header.forEach((_cell, ci) => { result += `| ${'-'.repeat(lengths[ci])} `; }); + result += '|\n'; + + // cells + rows.forEach(row => { + row.forEach((cell, ci) => { + if (typeof cell !== 'undefined') { + result += `| ${cell + ' '.repeat(lengths[ci] - cell.toString().length)} `; + } + }); + result += '|\n'; + }); + + return result; } } diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index 87c9e64dd54e0..17a6f1a85fb31 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -1289,8 +1289,7 @@ export class DirtyDiffModel extends Disposable { this.repositoryDisposables.add(disposables); disposables.add(toDisposable(() => this.repositoryDisposables.delete(disposables))); - const onDidChange = Event.any(repository.provider.onDidChange, repository.provider.onDidChangeResources); - disposables.add(onDidChange(this.triggerDiff, this)); + disposables.add(repository.provider.onDidChangeResources(this.triggerDiff, this)); const onDidRemoveThis = Event.filter(this.scmService.onDidRemoveRepository, r => r === repository); disposables.add(onDidRemoveThis(() => dispose(disposables), null)); diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css index 0c72ca522f9ae..4ba122fa37019 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm.css +++ b/src/vs/workbench/contrib/scm/browser/media/scm.css @@ -168,6 +168,12 @@ line-height: 18px; } +.scm-view .monaco-list-row .history-item > .label-container > .label > .count { + font-size: 12px; + margin-left: 0; + padding-left: 4px; +} + .scm-view .monaco-list-row .history-item > .label-container > .label > .codicon { font-size: 14px; color: inherit !important; diff --git a/src/vs/workbench/contrib/scm/browser/scmHistoryViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmHistoryViewPane.ts index 4de2e1841eb22..79ae478779259 100644 --- a/src/vs/workbench/contrib/scm/browser/scmHistoryViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmHistoryViewPane.ts @@ -365,17 +365,27 @@ class HistoryItemRenderer implements ITreeRenderer { const labelConfig = this._badgesConfig.read(reader); - const firstColoredRef = historyItem.references?.find(ref => ref.color); templateData.labelContainer.textContent = ''; + const references = historyItem.references ? + historyItem.references.slice(0) : []; + + // If the first reference is colored, we render it + // separately since we have to show the description + // for the first colored reference. + if (references.length > 0 && references[0].color) { + this._renderBadge([references[0]], true, templateData); + + // Remove the rendered reference from the collection + references.splice(0, 1); + } + // Group history item references by color - const historyItemRefsByColor = groupBy2( - (historyItem.references ?? []), - ref => ref.color ? ref.color : ''); + const historyItemRefsByColor = groupBy2(references, ref => ref.color ? ref.color : ''); for (const [key, historyItemRefs] of Object.entries(historyItemRefsByColor)) { - // Skip badges with no color + // If needed skip badges without a color if (key === '' && labelConfig !== 'all') { continue; } @@ -383,35 +393,44 @@ class HistoryItemRenderer implements ITreeRenderer ThemeIcon.isThemeIcon(ref.icon) ? ref.icon.id : ''); for (const [key, historyItemRefs] of Object.entries(historyItemRefByIconId)) { - if (key === '' || historyItemRefs.length === 0) { + // Skip badges without an icon + if (key === '') { continue; } - this._renderBadge(historyItemRefs[0], historyItemRefs[0] === firstColoredRef, templateData); + this._renderBadge(historyItemRefs, false, templateData); } } })); } - private _renderBadge(historyItemRef: ISCMHistoryItemRef, showDescription: boolean, templateData: HistoryItemTemplate): void { - if (!ThemeIcon.isThemeIcon(historyItemRef.icon)) { + private _renderBadge(historyItemRefs: ISCMHistoryItemRef[], showDescription: boolean, templateData: HistoryItemTemplate): void { + if (historyItemRefs.length === 0 || !ThemeIcon.isThemeIcon(historyItemRefs[0].icon)) { return; } const elements = h('div.label', { style: { - color: historyItemRef.color ? asCssVariable(historyItemHoverLabelForeground) : asCssVariable(foreground), - backgroundColor: historyItemRef.color ? asCssVariable(historyItemRef.color) : asCssVariable(historyItemHoverDefaultLabelBackground) + color: historyItemRefs[0].color ? asCssVariable(historyItemHoverLabelForeground) : asCssVariable(foreground), + backgroundColor: historyItemRefs[0].color ? asCssVariable(historyItemRefs[0].color) : asCssVariable(historyItemHoverDefaultLabelBackground) } }, [ + h('div.count@count', { + style: { + display: historyItemRefs.length > 1 ? '' : 'none' + } + }), h('div.icon@icon'), - h('div.description@description') + h('div.description@description', { + style: { + display: showDescription ? '' : 'none' + } + }) ]); - elements.icon.classList.add(...ThemeIcon.asClassNameArray(historyItemRef.icon)); - - elements.description.textContent = historyItemRef.name; - elements.description.style.display = showDescription ? '' : 'none'; + elements.count.textContent = historyItemRefs.length > 1 ? historyItemRefs.length.toString() : ''; + elements.icon.classList.add(...ThemeIcon.asClassNameArray(historyItemRefs[0].icon)); + elements.description.textContent = showDescription ? historyItemRefs[0].name : ''; append(templateData.labelContainer, elements.root); } diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index 7a005631e8d22..57350808cc0bd 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -2449,7 +2449,12 @@ export class SCMViewPane extends ViewPane { for (const repository of added) { const repositoryDisposables = new DisposableStore(); - repositoryDisposables.add(repository.provider.onDidChange(() => this.updateChildren(repository))); + repositoryDisposables.add(autorun(reader => { + /** @description action button */ + repository.provider.actionButton.read(reader); + this.updateChildren(repository); + })); + repositoryDisposables.add(repository.input.onDidChangeVisibility(() => this.updateChildren(repository))); repositoryDisposables.add(repository.provider.onDidChangeResourceGroups(() => this.updateChildren(repository))); @@ -2835,7 +2840,7 @@ class SCMTreeDataSource extends Disposable implements IAsyncDataSource await this.executeCommand(button.command.id, ...(button.command.arguments || [])), null, this.disposables.value); diff --git a/src/vs/workbench/contrib/scm/common/scm.ts b/src/vs/workbench/contrib/scm/common/scm.ts index 198caf34a60b1..74623463fa556 100644 --- a/src/vs/workbench/contrib/scm/common/scm.ts +++ b/src/vs/workbench/contrib/scm/common/scm.ts @@ -78,9 +78,8 @@ export interface ISCMProvider extends IDisposable { readonly commitTemplate: IObservable; readonly historyProvider: IObservable; readonly acceptInputCommand?: Command; - readonly actionButton?: ISCMActionButtonDescriptor; + readonly actionButton: IObservable; readonly statusBarCommands: IObservable; - readonly onDidChange: Event; getOriginalResource(uri: URI): Promise; } @@ -116,16 +115,15 @@ export interface ISCMInputChangeEvent { } export interface ISCMActionButtonDescriptor { - command: Command; + command: Command & { shortTitle?: string }; secondaryCommands?: Command[][]; - description?: string; enabled: boolean; } export interface ISCMActionButton { readonly type: 'actionButton'; readonly repository: ISCMRepository; - readonly button?: ISCMActionButtonDescriptor; + readonly button: ISCMActionButtonDescriptor; } export interface ISCMInput { diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index b4f6779650213..acd54b82ede05 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -7,7 +7,7 @@ import { IDimension } from '../../../../base/browser/dom.js'; import { Orientation } from '../../../../base/browser/ui/splitview/splitview.js'; import { Color } from '../../../../base/common/color.js'; import { Event, IDynamicListEventMultiplexer, type DynamicListEventMultiplexer } from '../../../../base/common/event.js'; -import { DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; +import { DisposableStore, IDisposable, type IReference } from '../../../../base/common/lifecycle.js'; import { OperatingSystem } from '../../../../base/common/platform.js'; import { URI } from '../../../../base/common/uri.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; @@ -628,7 +628,8 @@ export interface ITerminalInstance extends IBaseTerminalInstance { /** * The position of the terminal. */ - target?: TerminalLocation; + target: TerminalLocation | undefined; + targetRef: IReference; /** * The id of a persistent process. This is defined if this is a terminal created by a pty host diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEvents.ts b/src/vs/workbench/contrib/terminal/browser/terminalEvents.ts index c0ae3bc97ff5a..46b4481f9683c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEvents.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEvents.ts @@ -17,14 +17,19 @@ export function createInstanceCapabilityEventMultiplexer { const store = new DisposableStore(); const multiplexer = store.add(new EventMultiplexer<{ instance: ITerminalInstance; data: K }>()); - const capabilityListeners = store.add(new DisposableMap()); + const capabilityListeners = store.add(new DisposableMap>()); function addCapability(instance: ITerminalInstance, capability: ITerminalCapabilityImplMap[T]) { const listener = multiplexer.add(Event.map(getEvent(capability), data => ({ instance, data }))); - capabilityListeners.set(capability, listener); + let instanceCapabilityListeners = capabilityListeners.get(instance.instanceId); + if (!instanceCapabilityListeners) { + instanceCapabilityListeners = new DisposableMap(); + capabilityListeners.set(instance.instanceId, instanceCapabilityListeners); + } + instanceCapabilityListeners.set(capability, listener); } - // Existing capabilities + // Existing instances for (const instance of currentInstances) { const capability = instance.capabilities.get(capabilityId); if (capability) { @@ -32,6 +37,11 @@ export function createInstanceCapabilityEventMultiplexer { + capabilityListeners.deleteAndDispose(instance.instanceId); + })); + // Added capabilities const addCapabilityMultiplexer = store.add(new DynamicListEventMultiplexer( currentInstances, @@ -50,11 +60,11 @@ export function createInstanceCapabilityEventMultiplexer instance.capabilities.onDidRemoveCapability + instance => Event.map(instance.capabilities.onDidRemoveCapability, changeEvent => ({ instance, changeEvent })) )); store.add(removeCapabilityMultiplexer.event(e => { - if (e.id === capabilityId) { - capabilityListeners.deleteAndDispose(e.capability); + if (e.changeEvent.id === capabilityId) { + capabilityListeners.get(e.instance.instanceId)?.deleteAndDispose(e.changeEvent.id); } })); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index f90969a2c60c4..bac17da1e196b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -17,7 +17,7 @@ import { ErrorNoTelemetry, onUnexpectedError } from '../../../../base/common/err import { Emitter, Event } from '../../../../base/common/event.js'; import { KeyCode } from '../../../../base/common/keyCodes.js'; import { ISeparator, template } from '../../../../base/common/labels.js'; -import { Disposable, DisposableStore, IDisposable, MutableDisposable, dispose, toDisposable } from '../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore, IDisposable, ImmortalReference, MutableDisposable, dispose, toDisposable, type IReference } from '../../../../base/common/lifecycle.js'; import { Schemas } from '../../../../base/common/network.js'; import * as path from '../../../../base/common/path.js'; import { OS, OperatingSystem, isMacintosh, isWindows } from '../../../../base/common/platform.js'; @@ -188,7 +188,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _labelComputer?: TerminalLabelComputer; private _userHome?: string; private _hasScrollBar?: boolean; - private _target?: TerminalLocation | undefined; private _usedShellIntegrationInjection: boolean = false; get usedShellIntegrationInjection(): boolean { return this._usedShellIntegrationInjection; } private _lineDataEventAddon: LineDataEventAddon | undefined; @@ -216,9 +215,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._shellLaunchConfig.waitOnExit = value; } - get target(): TerminalLocation | undefined { return this._target; } + private _targetRef: ImmortalReference = new ImmortalReference(undefined); + get targetRef(): IReference { return this._targetRef; } + + get target(): TerminalLocation | undefined { return this._targetRef.object; } set target(value: TerminalLocation | undefined) { - this._target = value; + this._targetRef.object = value; this._onDidChangeTarget.fire(value); } @@ -317,10 +319,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { readonly onData = this._onData.event; private readonly _onBinary = this._register(new Emitter()); readonly onBinary = this._onBinary.event; - private readonly _onLineData = this._register(new Emitter({ - onDidAddFirstListener: () => this._onLineDataSetup() - })); - readonly onLineData = this._onLineData.event; private readonly _onRequestExtHostProcess = this._register(new Emitter()); readonly onRequestExtHostProcess = this._onRequestExtHostProcess.event; private readonly _onDimensionsChanged = this._register(new Emitter()); @@ -357,6 +355,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private readonly _onDidPaste = this._register(new Emitter()); readonly onDidPaste = this._onDidPaste.event; + private readonly _onLineData = this._register(new Emitter({ + onDidAddFirstListener: async () => (this.xterm ?? await this._xtermReadyPromise).raw.loadAddon(this._lineDataEventAddon!) + })); + readonly onLineData = this._onLineData.event; + constructor( private readonly _terminalShellTypeContextKey: IContextKey, private readonly _terminalInRunCommandPicker: IContextKey, @@ -753,7 +756,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { Terminal, this._cols, this._rows, - this._scopedInstantiationService.createInstance(TerminalInstanceColorProvider, this), + undefined, + this._scopedInstantiationService.createInstance(TerminalInstanceColorProvider, this._targetRef), this.capabilities, this._processManager.shellIntegrationNonce, disableShellIntegrationReporting @@ -775,6 +779,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { await this._updatePtyDimensions(xterm.raw); } )); + this._register(toDisposable(() => this._resizeDebouncer = undefined)); this.updateAccessibilitySupport(); this._register(this.xterm.onDidRequestRunCommand(e => { if (e.copyAsHtml) { @@ -863,11 +868,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return xterm; } - private async _onLineDataSetup(): Promise { - const xterm = this.xterm || await this._xtermReadyPromise; - xterm.raw.loadAddon(this._lineDataEventAddon!); - } - async runCommand(commandLine: string, shouldExecute: boolean): Promise { let commandDetection = this.capabilities.get(TerminalCapability.CommandDetection); @@ -2676,7 +2676,7 @@ export function parseExitResult( export class TerminalInstanceColorProvider implements IXtermColorProvider { constructor( - private readonly _instance: ITerminalInstance, + private readonly _target: IReference, @IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService, ) { } @@ -2686,7 +2686,7 @@ export class TerminalInstanceColorProvider implements IXtermColorProvider { if (terminalBackground) { return terminalBackground; } - if (this._instance.target === TerminalLocation.Editor) { + if (this._target.object === TerminalLocation.Editor) { return theme.getColor(editorBackground); } const location = this._viewDescriptorService.getViewLocationById(TERMINAL_VIEW_ID)!; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index b1da8a45dd898..88a2aace6aeca 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -1028,6 +1028,7 @@ export class TerminalService extends Disposable implements ITerminalService { ctor, options.cols, options.rows, + undefined, options.colorProvider, options.capabilities || new TerminalCapabilityStore(), '', diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermAddonImporter.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermAddonImporter.ts new file mode 100644 index 0000000000000..b78debc63c2ba --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermAddonImporter.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type { ClipboardAddon as ClipboardAddonType } from '@xterm/addon-clipboard'; +import type { ImageAddon as ImageAddonType } from '@xterm/addon-image'; +import type { SearchAddon as SearchAddonType } from '@xterm/addon-search'; +import type { SerializeAddon as SerializeAddonType } from '@xterm/addon-serialize'; +import type { Unicode11Addon as Unicode11AddonType } from '@xterm/addon-unicode11'; +import type { WebglAddon as WebglAddonType } from '@xterm/addon-webgl'; +import { importAMDNodeModule } from '../../../../../amdX.js'; + +export interface IXtermAddonNameToCtor { + clipboard: typeof ClipboardAddonType; + image: typeof ImageAddonType; + search: typeof SearchAddonType; + serialize: typeof SerializeAddonType; + unicode11: typeof Unicode11AddonType; + webgl: typeof WebglAddonType; +} + +// This interface lets a maps key and value be linked with generics +interface IImportedXtermAddonMap extends Map { + get(name: K): IXtermAddonNameToCtor[K] | undefined; + set(name: K, value: IXtermAddonNameToCtor[K]): this; +} + +const importedAddons: IImportedXtermAddonMap = new Map(); + +/** + * Exposes a simple interface to consumers, encapsulating the messy import xterm + * addon import and caching logic. + */ +export class XtermAddonImporter { + async importAddon(name: T): Promise { + let addon = importedAddons.get(name); + if (!addon) { + switch (name) { + case 'clipboard': addon = (await importAMDNodeModule('@xterm/addon-clipboard', 'lib/addon-clipboard.js')).ClipboardAddon as IXtermAddonNameToCtor[T]; break; + case 'image': addon = (await importAMDNodeModule('@xterm/addon-image', 'lib/addon-image.js')).ImageAddon as IXtermAddonNameToCtor[T]; break; + case 'search': addon = (await importAMDNodeModule('@xterm/addon-search', 'lib/addon-search.js')).SearchAddon as IXtermAddonNameToCtor[T]; break; + case 'serialize': addon = (await importAMDNodeModule('@xterm/addon-serialize', 'lib/addon-serialize.js')).SerializeAddon as IXtermAddonNameToCtor[T]; break; + case 'unicode11': addon = (await importAMDNodeModule('@xterm/addon-unicode11', 'lib/addon-unicode11.js')).Unicode11Addon as IXtermAddonNameToCtor[T]; break; + case 'webgl': addon = (await importAMDNodeModule('@xterm/addon-webgl', 'lib/addon-webgl.js')).WebglAddon as IXtermAddonNameToCtor[T]; break; + } + if (!addon) { + throw new Error(`Could not load addon ${name}`); + } + importedAddons.set(name, addon); + } + return addon as IXtermAddonNameToCtor[T]; + } +} diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index c5bd84fa99799..9683b7597a642 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -31,7 +31,6 @@ import { DecorationAddon } from './decorationAddon.js'; import { ITerminalCapabilityStore, ITerminalCommand, TerminalCapability } from '../../../../../platform/terminal/common/capabilities/capabilities.js'; import { Emitter } from '../../../../../base/common/event.js'; import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js'; -import { importAMDNodeModule } from '../../../../../amdX.js'; import { IContextKey, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { TerminalContextKeys } from '../../common/terminalContextKey.js'; import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js'; @@ -41,17 +40,12 @@ import { IMouseWheelEvent, StandardWheelEvent } from '../../../../../base/browse import { ILayoutService } from '../../../../../platform/layout/browser/layoutService.js'; import { AccessibilitySignal, IAccessibilitySignalService } from '../../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js'; import { scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from '../../../../../platform/theme/common/colorRegistry.js'; +import { XtermAddonImporter } from './xtermAddonImporter.js'; const enum RenderConstants { SmoothScrollDuration = 125 } -let ClipboardAddon: typeof ClipboardAddonType; -let ImageAddon: typeof ImageAddonType; -let SearchAddon: typeof SearchAddonType; -let SerializeAddon: typeof SerializeAddonType; -let Unicode11Addon: typeof Unicode11AddonType; -let WebglAddon: typeof WebglAddonType; function getFullBufferLineAsString(lineIndex: number, buffer: IBuffer): { lineData: string | undefined; lineIndex: number } { let line = buffer.getLine(lineIndex); @@ -180,6 +174,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach xtermCtor: typeof RawXtermTerminal, cols: number, rows: number, + private readonly _xtermAddonLoader: XtermAddonImporter = new XtermAddonImporter(), private readonly _xtermColorProvider: IXtermColorProvider, private readonly _capabilities: ITerminalCapabilityStore, shellIntegrationNonce: string, @@ -281,7 +276,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach this.raw.loadAddon(this._decorationAddon); this._shellIntegrationAddon = new ShellIntegrationAddon(shellIntegrationNonce, disableShellIntegrationReporting, this._telemetryService, this._logService); this.raw.loadAddon(this._shellIntegrationAddon); - this._getClipboardAddonConstructor().then(ClipboardAddon => { + this._xtermAddonLoader.importAddon('clipboard').then(ClipboardAddon => { this._clipboardAddon = this._instantiationService.createInstance(ClipboardAddon, undefined, { async readText(type: ClipboardSelectionType): Promise { return _clipboardService.readText(type === 'p' ? 'selection' : 'clipboard'); @@ -309,7 +304,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach async getContentsAsHtml(): Promise { if (!this._serializeAddon) { - const Addon = await this._getSerializeAddonConstructor(); + const Addon = await this._xtermAddonLoader.importAddon('serialize'); this._serializeAddon = new Addon(); this.raw.loadAddon(this._serializeAddon); } @@ -319,7 +314,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach async getSelectionAsHtml(command?: ITerminalCommand): Promise { if (!this._serializeAddon) { - const Addon = await this._getSerializeAddonConstructor(); + const Addon = await this._xtermAddonLoader.importAddon('serialize'); this._serializeAddon = new Addon(); this.raw.loadAddon(this._serializeAddon); } @@ -485,7 +480,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach private _searchAddonPromise: Promise | undefined; private _getSearchAddon(): Promise { if (!this._searchAddonPromise) { - this._searchAddonPromise = this._getSearchAddonConstructor().then((AddonCtor) => { + this._searchAddonPromise = this._xtermAddonLoader.importAddon('search').then((AddonCtor) => { this._searchAddon = new AddonCtor({ highlightLimit: XtermTerminalConstants.SearchHighlightLimit }); this.raw.loadAddon(this._searchAddon); this._searchAddon.onDidChangeResults((results: { resultIndex: number; resultCount: number }) => { @@ -687,7 +682,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach } } - const Addon = await this._getWebglAddonConstructor(); + const Addon = await this._xtermAddonLoader.importAddon('webgl'); this._webglAddon = new Addon(); try { this.raw.loadAddon(this._webglAddon); @@ -722,7 +717,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach // Only allow the image addon when webgl is being used to avoid possible GPU issues if (this._terminalConfigurationService.config.enableImages && this._webglAddon) { if (!this._imageAddon) { - const AddonCtor = await this._getImageAddonConstructor(); + const AddonCtor = await this._xtermAddonLoader.importAddon('image'); this._imageAddon = new AddonCtor(); this.raw.loadAddon(this._imageAddon); } @@ -736,48 +731,6 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach } } - protected async _getClipboardAddonConstructor(): Promise { - if (!ClipboardAddon) { - ClipboardAddon = (await importAMDNodeModule('@xterm/addon-clipboard', 'lib/addon-clipboard.js')).ClipboardAddon; - } - return ClipboardAddon; - } - - protected async _getImageAddonConstructor(): Promise { - if (!ImageAddon) { - ImageAddon = (await importAMDNodeModule('@xterm/addon-image', 'lib/addon-image.js')).ImageAddon; - } - return ImageAddon; - } - - protected async _getSearchAddonConstructor(): Promise { - if (!SearchAddon) { - SearchAddon = (await importAMDNodeModule('@xterm/addon-search', 'lib/addon-search.js')).SearchAddon; - } - return SearchAddon; - } - - protected async _getUnicode11Constructor(): Promise { - if (!Unicode11Addon) { - Unicode11Addon = (await importAMDNodeModule('@xterm/addon-unicode11', 'lib/addon-unicode11.js')).Unicode11Addon; - } - return Unicode11Addon; - } - - protected async _getWebglAddonConstructor(): Promise { - if (!WebglAddon) { - WebglAddon = (await importAMDNodeModule('@xterm/addon-webgl', 'lib/addon-webgl.js')).WebglAddon; - } - return WebglAddon; - } - - protected async _getSerializeAddonConstructor(): Promise { - if (!SerializeAddon) { - SerializeAddon = (await importAMDNodeModule('@xterm/addon-serialize', 'lib/addon-serialize.js')).SerializeAddon; - } - return SerializeAddon; - } - private _disposeOfWebglRenderer(): void { try { this._webglAddon?.dispose(); @@ -849,7 +802,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach private async _updateUnicodeVersion(): Promise { if (!this._unicode11Addon && this._terminalConfigurationService.config.unicodeVersion === '11') { - const Addon = await this._getUnicode11Constructor(); + const Addon = await this._xtermAddonLoader.importAddon('unicode11'); this._unicode11Addon = new Addon(); this.raw.loadAddon(this._unicode11Addon); } diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts index 82b32af67f009..ac776887732de 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts @@ -7,7 +7,6 @@ import type { WebglAddon } from '@xterm/addon-webgl'; import type { IEvent, Terminal } from '@xterm/xterm'; import { deepStrictEqual, strictEqual } from 'assert'; import { importAMDNodeModule } from '../../../../../../amdX.js'; -import { isSafari } from '../../../../../../base/browser/browser.js'; import { Color, RGBA } from '../../../../../../base/common/color.js'; import { Emitter } from '../../../../../../base/common/event.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js'; @@ -23,6 +22,7 @@ import { XtermTerminal } from '../../../browser/xterm/xtermTerminal.js'; import { ITerminalConfiguration, TERMINAL_VIEW_ID } from '../../../common/terminal.js'; import { registerColors, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_INACTIVE_SELECTION_BACKGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_SELECTION_FOREGROUND_COLOR } from '../../../common/terminalColorRegistry.js'; import { workbenchInstantiationService } from '../../../../../test/browser/workbenchTestServices.js'; +import { IXtermAddonNameToCtor, XtermAddonImporter } from '../../../browser/xterm/xtermAddonImporter.js'; registerColors(); @@ -45,11 +45,12 @@ class TestWebglAddon implements WebglAddon { clearTextureAtlas() { } } -class TestXtermTerminal extends XtermTerminal { - webglAddonPromise: Promise = Promise.resolve(TestWebglAddon); - // Force synchronous to avoid async when activating the addon - protected override _getWebglAddonConstructor() { - return this.webglAddonPromise; +class TestXtermAddonImporter extends XtermAddonImporter { + override async importAddon(name: T): Promise { + if (name === 'webgl') { + return Promise.resolve(TestWebglAddon) as any; + } + return super.importAddon(name); } } @@ -90,7 +91,7 @@ suite('XtermTerminal', () => { let instantiationService: TestInstantiationService; let configurationService: TestConfigurationService; let themeService: TestThemeService; - let xterm: TestXtermTerminal; + let xterm: XtermTerminal; let XTermBaseCtor: typeof Terminal; setup(async () => { @@ -113,7 +114,7 @@ suite('XtermTerminal', () => { XTermBaseCtor = (await importAMDNodeModule('@xterm/xterm', 'lib/xterm.js')).Terminal; const capabilityStore = store.add(new TerminalCapabilityStore()); - xterm = store.add(instantiationService.createInstance(TestXtermTerminal, XTermBaseCtor, 80, 30, { getBackgroundColor: () => undefined }, capabilityStore, '', true)); + xterm = store.add(instantiationService.createInstance(XtermTerminal, XTermBaseCtor, 80, 30, new TestXtermAddonImporter(), { getBackgroundColor: () => undefined }, capabilityStore, '', true)); TestWebglAddon.shouldThrow = false; TestWebglAddon.isEnabled = false; @@ -130,7 +131,7 @@ suite('XtermTerminal', () => { [PANEL_BACKGROUND]: '#ff0000', [SIDE_BAR_BACKGROUND]: '#00ff00' })); - xterm = store.add(instantiationService.createInstance(XtermTerminal, XTermBaseCtor, 80, 30, { getBackgroundColor: () => new Color(new RGBA(255, 0, 0)) }, store.add(new TerminalCapabilityStore()), '', true)); + xterm = store.add(instantiationService.createInstance(XtermTerminal, XTermBaseCtor, 80, 30, new TestXtermAddonImporter(), { getBackgroundColor: () => new Color(new RGBA(255, 0, 0)) }, store.add(new TerminalCapabilityStore()), '', true)); strictEqual(xterm.raw.options.theme?.background, '#ff0000'); }); test('should react to and apply theme changes', () => { @@ -159,7 +160,7 @@ suite('XtermTerminal', () => { 'terminal.ansiBrightCyan': '#150000', 'terminal.ansiBrightWhite': '#160000', })); - xterm = store.add(instantiationService.createInstance(XtermTerminal, XTermBaseCtor, 80, 30, { getBackgroundColor: () => undefined }, store.add(new TerminalCapabilityStore()), '', true)); + xterm = store.add(instantiationService.createInstance(XtermTerminal, XTermBaseCtor, 80, 30, new TestXtermAddonImporter(), { getBackgroundColor: () => undefined }, store.add(new TerminalCapabilityStore()), '', true)); deepStrictEqual(xterm.raw.options.theme, { background: undefined, foreground: '#000200', @@ -245,40 +246,4 @@ suite('XtermTerminal', () => { }); }); }); - - suite('renderers', () => { - // This is skipped until the webgl renderer bug is fixed in Chromium - // https://bugs.chromium.org/p/chromium/issues/detail?id=1476475 - test.skip('should re-evaluate gpu acceleration auto when the setting is changed', async () => { - // Check initial state - strictEqual(TestWebglAddon.isEnabled, false); - - // Open xterm as otherwise the webgl addon won't activate - const container = document.createElement('div'); - xterm.attachToElement(container); - - // Auto should activate the webgl addon - await configurationService.setUserConfiguration('terminal', { integrated: { ...defaultTerminalConfig, gpuAcceleration: 'auto' } }); - configurationService.onDidChangeConfigurationEmitter.fire({ affectsConfiguration: () => true } as any); - await xterm.webglAddonPromise; // await addon activate - if (isSafari) { - strictEqual(TestWebglAddon.isEnabled, false, 'The webgl renderer is always disabled on Safari'); - } else { - strictEqual(TestWebglAddon.isEnabled, true); - } - - // Turn off to reset state - await configurationService.setUserConfiguration('terminal', { integrated: { ...defaultTerminalConfig, gpuAcceleration: 'off' } }); - configurationService.onDidChangeConfigurationEmitter.fire({ affectsConfiguration: () => true } as any); - await xterm.webglAddonPromise; // await addon activate - strictEqual(TestWebglAddon.isEnabled, false); - - // Set to auto again but throw when activating the webgl addon - TestWebglAddon.shouldThrow = true; - await configurationService.setUserConfiguration('terminal', { integrated: { ...defaultTerminalConfig, gpuAcceleration: 'auto' } }); - configurationService.onDidChangeConfigurationEmitter.fire({ affectsConfiguration: () => true } as any); - await xterm.webglAddonPromise; // await addon activate - strictEqual(TestWebglAddon.isEnabled, false); - }); - }); }); diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index e2c5d9e3a5e64..bd476ae6bdd6f 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -79,7 +79,7 @@ suite('Buffer Content Tracker', () => { capabilities.add(TerminalCapability.NaiveCwdDetection, null!); } const TerminalCtor = (await importAMDNodeModule('@xterm/xterm', 'lib/xterm.js')).Terminal; - xterm = store.add(instantiationService.createInstance(XtermTerminal, TerminalCtor, 80, 30, { getBackgroundColor: () => undefined }, capabilities, '', true)); + xterm = store.add(instantiationService.createInstance(XtermTerminal, TerminalCtor, 80, 30, undefined, { getBackgroundColor: () => undefined }, capabilities, '', true)); const container = document.createElement('div'); xterm.raw.open(container); configurationService = new TestConfigurationService({ terminal: { integrated: { tabs: { separator: ' - ', title: '${cwd}', description: '${cwd}' } } } }); diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts index a86483a6a6fcf..6aac826a90366 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts @@ -104,12 +104,7 @@ export class TerminalChatWidget extends Disposable { this._focusTracker = this._register(trackFocus(this._container)); this._register(this._focusTracker.onDidFocus(() => this._focusedContextKey.set(true))); - this._register(this._focusTracker.onDidBlur(() => { - this._focusedContextKey.set(false); - if (!this.inlineChatWidget.responseContent) { - this.hide(); - } - })); + this._register(this._focusTracker.onDidBlur(() => this._focusedContextKey.set(false))); this.hide(); } diff --git a/src/vs/workbench/contrib/terminalContrib/commandGuide/browser/terminal.commandGuide.contribution.ts b/src/vs/workbench/contrib/terminalContrib/commandGuide/browser/terminal.commandGuide.contribution.ts index 7051364ea44ff..ef18811c74866 100644 --- a/src/vs/workbench/contrib/terminalContrib/commandGuide/browser/terminal.commandGuide.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/commandGuide/browser/terminal.commandGuide.contribution.ts @@ -42,11 +42,11 @@ class TerminalCommandGuideContribution extends Disposable implements ITerminalCo xtermOpen(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void { this._xterm = xterm; this._refreshActivatedState(); - this._configurationService.onDidChangeConfiguration(e => { + this._register(this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(TerminalCommandGuideSettingId.ShowCommandGuide)) { this._refreshActivatedState(); } - }); + })); } private _refreshActivatedState() { @@ -80,7 +80,7 @@ class TerminalCommandGuideContribution extends Disposable implements ITerminalCo if (!rect) { return; } - const mouseCursorY = Math.floor(e.offsetY / (rect.height / xterm.raw.rows)); + const mouseCursorY = Math.floor((e.clientY - rect.top) / (rect.height / xterm.raw.rows)); const command = this._instance.capabilities.get(TerminalCapability.CommandDetection)?.getCommandForLine(xterm.raw.buffer.active.viewportY + mouseCursorY); if (command && 'getOutput' in command) { xterm.markTracker.showCommandGuide(command); diff --git a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts index bd9447f80013c..5ee9ea2db8d30 100644 --- a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts @@ -7,7 +7,7 @@ import type { Terminal } from '@xterm/xterm'; import { Delayer } from '../../../../../base/common/async.js'; import { VSBuffer } from '../../../../../base/common/buffer.js'; import { Event } from '../../../../../base/common/event.js'; -import { Disposable, DisposableStore, IDisposable, MutableDisposable, combinedDisposable, dispose } from '../../../../../base/common/lifecycle.js'; +import { Disposable, DisposableMap, DisposableStore, IDisposable, MutableDisposable, combinedDisposable, dispose } from '../../../../../base/common/lifecycle.js'; import { URI } from '../../../../../base/common/uri.js'; import './media/developer.css'; import { localize, localize2 } from '../../../../../nls.js'; @@ -256,8 +256,11 @@ class DevModeContribution extends Disposable implements ITerminalContribution { const commandDetection = this._instance.capabilities.get(TerminalCapability.CommandDetection); if (devMode) { if (commandDetection) { - const commandDecorations = new Map(); + const commandDecorations = new DisposableMap(); + const otherDisposables = new DisposableStore(); this._activeDevModeDisposables.value = combinedDisposable( + commandDecorations, + otherDisposables, // Prompt input this._instance.onDidBlur(() => this._updateDevMode()), this._instance.onDidFocus(() => this._updateDevMode()), @@ -266,17 +269,17 @@ class DevModeContribution extends Disposable implements ITerminalContribution { commandDetection.onCommandFinished(command => { const colorClass = `color-${this._currentColor}`; const decorations: IDisposable[] = []; - commandDecorations.set(command, decorations); + commandDecorations.set(command, combinedDisposable(...decorations)); if (command.promptStartMarker) { const d = this._instance.xterm!.raw?.registerDecoration({ marker: command.promptStartMarker }); if (d) { decorations.push(d); - d.onRender(e => { + otherDisposables.add(d.onRender(e => { e.textContent = 'A'; e.classList.add('xterm-sequence-decoration', 'top', 'left', colorClass); - }); + })); } } if (command.marker) { @@ -286,10 +289,10 @@ class DevModeContribution extends Disposable implements ITerminalContribution { }); if (d) { decorations.push(d); - d.onRender(e => { + otherDisposables.add(d.onRender(e => { e.textContent = 'B'; e.classList.add('xterm-sequence-decoration', 'top', 'right', colorClass); - }); + })); } } if (command.executedMarker) { @@ -299,10 +302,10 @@ class DevModeContribution extends Disposable implements ITerminalContribution { }); if (d) { decorations.push(d); - d.onRender(e => { + otherDisposables.add(d.onRender(e => { e.textContent = 'C'; e.classList.add('xterm-sequence-decoration', 'bottom', 'left', colorClass); - }); + })); } } if (command.endMarker) { @@ -311,10 +314,10 @@ class DevModeContribution extends Disposable implements ITerminalContribution { }); if (d) { decorations.push(d); - d.onRender(e => { + otherDisposables.add(d.onRender(e => { e.textContent = 'D'; e.classList.add('xterm-sequence-decoration', 'bottom', 'right', colorClass); - }); + })); } } this._currentColor = (this._currentColor + 1) % 2; @@ -325,7 +328,7 @@ class DevModeContribution extends Disposable implements ITerminalContribution { if (decorations) { dispose(decorations); } - commandDecorations.delete(c); + commandDecorations.deleteAndDispose(c); } }) ); diff --git a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLink.ts b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLink.ts index d9bd159bfc9a3..228d047f4b254 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLink.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLink.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import type { IViewportRange, IBufferRange, ILink, ILinkDecorations, Terminal } from '@xterm/xterm'; -import { DisposableStore } from '../../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore, MutableDisposable } from '../../../../../base/common/lifecycle.js'; import * as dom from '../../../../../base/browser/dom.js'; import { RunOnceScheduler } from '../../../../../base/common/async.js'; import { convertBufferRangeToViewport } from './terminalLinkHelpers.js'; @@ -16,12 +16,11 @@ import type { URI } from '../../../../../base/common/uri.js'; import type { IParsedLink } from './terminalLinkParsing.js'; import type { IHoverAction } from '../../../../../base/browser/ui/hover/hover.js'; -export class TerminalLink extends DisposableStore implements ILink { +export class TerminalLink extends Disposable implements ILink { decorations: ILinkDecorations; - asyncActivate: Promise | undefined; - private _tooltipScheduler: RunOnceScheduler | undefined; - private _hoverListeners: DisposableStore | undefined; + private readonly _tooltipScheduler: MutableDisposable = this._register(new MutableDisposable()); + private readonly _hoverListeners = this._register(new MutableDisposable()); private readonly _onInvalidated = new Emitter(); get onInvalidated(): Event { return this._onInvalidated.event; } @@ -50,38 +49,28 @@ export class TerminalLink extends DisposableStore implements ILink { }; } - override dispose(): void { - super.dispose(); - this._hoverListeners?.dispose(); - this._hoverListeners = undefined; - this._tooltipScheduler?.dispose(); - this._tooltipScheduler = undefined; - } - activate(event: MouseEvent | undefined, text: string): void { - // Trigger the xterm.js callback synchronously but track the promise resolution so we can - // use it in tests - this.asyncActivate = this._activateCallback(event, text); + this._activateCallback(event, text); } hover(event: MouseEvent, text: string): void { const w = dom.getWindow(event); const d = w.document; // Listen for modifier before handing it off to the hover to handle so it gets disposed correctly - this._hoverListeners = new DisposableStore(); - this._hoverListeners.add(dom.addDisposableListener(d, 'keydown', e => { + const hoverListeners = this._hoverListeners.value = new DisposableStore(); + hoverListeners.add(dom.addDisposableListener(d, 'keydown', e => { if (!e.repeat && this._isModifierDown(e)) { this._enableDecorations(); } })); - this._hoverListeners.add(dom.addDisposableListener(d, 'keyup', e => { + hoverListeners.add(dom.addDisposableListener(d, 'keyup', e => { if (!e.repeat && !this._isModifierDown(e)) { this._disableDecorations(); } })); // Listen for when the terminal renders on the same line as the link - this._hoverListeners.add(this._xterm.onRender(e => { + hoverListeners.add(this._xterm.onRender(e => { const viewportRangeY = this.range.start.y - this._viewportY; if (viewportRangeY >= e.start && viewportRangeY <= e.end) { this._onInvalidated.fire(); @@ -91,7 +80,7 @@ export class TerminalLink extends DisposableStore implements ILink { // Only show the tooltip and highlight for high confidence links (not word/search workspace // links). Feedback was that this makes using the terminal overly noisy. if (this._isHighConfidenceLink) { - this._tooltipScheduler = new RunOnceScheduler(() => { + this._tooltipScheduler.value = new RunOnceScheduler(() => { this._tooltipCallback( this, convertBufferRangeToViewport(this.range, this._viewportY), @@ -99,15 +88,13 @@ export class TerminalLink extends DisposableStore implements ILink { this._isHighConfidenceLink ? () => this._disableDecorations() : undefined ); // Clear out scheduler until next hover event - this._tooltipScheduler?.dispose(); - this._tooltipScheduler = undefined; + this._tooltipScheduler.clear(); }, this._configurationService.getValue('workbench.hover.delay')); - this.add(this._tooltipScheduler); - this._tooltipScheduler.schedule(); + this._tooltipScheduler.value.schedule(); } const origin = { x: event.pageX, y: event.pageY }; - this._hoverListeners.add(dom.addDisposableListener(d, dom.EventType.MOUSE_MOVE, e => { + hoverListeners.add(dom.addDisposableListener(d, dom.EventType.MOUSE_MOVE, e => { // Update decorations if (this._isModifierDown(e)) { this._enableDecorations(); @@ -119,16 +106,14 @@ export class TerminalLink extends DisposableStore implements ILink { if (Math.abs(e.pageX - origin.x) > w.devicePixelRatio * 2 || Math.abs(e.pageY - origin.y) > w.devicePixelRatio * 2) { origin.x = e.pageX; origin.y = e.pageY; - this._tooltipScheduler?.schedule(); + this._tooltipScheduler.value?.schedule(); } })); } leave(): void { - this._hoverListeners?.dispose(); - this._hoverListeners = undefined; - this._tooltipScheduler?.dispose(); - this._tooltipScheduler = undefined; + this._hoverListeners.clear(); + this._tooltipScheduler.clear(); } private _enableDecorations(): void { diff --git a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts index 7f148d7fecf15..4ff47d600d311 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts @@ -109,14 +109,19 @@ function generateLinkSuffixRegex(eolOnly: boolean) { // "foo", lines 339-341 [#171880] // "foo", lines 339-341, characters 12-789 [#178287] `['"]?(?:,? |: ?| on )lines? ${r()}(?:-${re()})?(?:,? (?:col(?:umn)?|characters?) ${c()}(?:-${ce()})?)?` + eolSuffix, + // () and [] are interchangeable // foo(339) // foo(339,12) // foo(339, 12) // foo (339) - // ... + // foo (339,12) + // foo (339, 12) // foo: (339) - // ... - `:? ?[\\[\\(]${r()}(?:, ?${c()})?[\\]\\)]` + eolSuffix, + // foo: (339,12) + // foo: (339, 12) + // foo(339:12) [#229842] + // foo (339:12) [#229842] + `:? ?[\\[\\(]${r()}(?:(?:, ?|:)${c()})?[\\]\\)]` + eolSuffix, ]; const suffixClause = lineAndColumnRegexClauses diff --git a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkParsing.test.ts b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkParsing.test.ts index 3f61393ab7110..099e639ee820e 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkParsing.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkParsing.test.ts @@ -125,6 +125,8 @@ const testLinks: ITestLink[] = [ { link: 'foo: (339)', prefix: undefined, suffix: ': (339)', hasRow: true, hasCol: false }, { link: 'foo: (339,12)', prefix: undefined, suffix: ': (339,12)', hasRow: true, hasCol: true }, { link: 'foo: (339, 12)', prefix: undefined, suffix: ': (339, 12)', hasRow: true, hasCol: true }, + { link: 'foo(339:12)', prefix: undefined, suffix: '(339:12)', hasRow: true, hasCol: true }, + { link: 'foo (339:12)', prefix: undefined, suffix: ' (339:12)', hasRow: true, hasCol: true }, // Square brackets { link: 'foo[339]', prefix: undefined, suffix: '[339]', hasRow: true, hasCol: false }, @@ -136,6 +138,8 @@ const testLinks: ITestLink[] = [ { link: 'foo: [339]', prefix: undefined, suffix: ': [339]', hasRow: true, hasCol: false }, { link: 'foo: [339,12]', prefix: undefined, suffix: ': [339,12]', hasRow: true, hasCol: true }, { link: 'foo: [339, 12]', prefix: undefined, suffix: ': [339, 12]', hasRow: true, hasCol: true }, + { link: 'foo[339:12]', prefix: undefined, suffix: '[339:12]', hasRow: true, hasCol: true }, + { link: 'foo [339:12]', prefix: undefined, suffix: ' [339:12]', hasRow: true, hasCol: true }, // OCaml-style { link: '"foo", line 339, character 12', prefix: '"', suffix: '", line 339, character 12', hasRow: true, hasCol: true }, diff --git a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLocalLinkDetector.test.ts b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLocalLinkDetector.test.ts index 70d503f1526ef..df3d642769a3e 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLocalLinkDetector.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLocalLinkDetector.test.ts @@ -110,6 +110,8 @@ const supportedLinkFormats: LinkFormatInfo[] = [ { urlFormat: '{0}({1}, {2})', line: '5', column: '3' }, { urlFormat: '{0} ({1}, {2})', line: '5', column: '3' }, { urlFormat: '{0}: ({1}, {2})', line: '5', column: '3' }, + { urlFormat: '{0}({1}:{2})', line: '5', column: '3' }, + { urlFormat: '{0} ({1}:{2})', line: '5', column: '3' }, { urlFormat: '{0}:{1}', line: '5' }, { urlFormat: '{0}:{1}:{2}', line: '5', column: '3' }, { urlFormat: '{0} {1}:{2}', line: '5', column: '3' }, @@ -121,6 +123,8 @@ const supportedLinkFormats: LinkFormatInfo[] = [ { urlFormat: '{0}[{1}, {2}]', line: '5', column: '3' }, { urlFormat: '{0} [{1}, {2}]', line: '5', column: '3' }, { urlFormat: '{0}: [{1}, {2}]', line: '5', column: '3' }, + { urlFormat: '{0}[{1}:{2}]', line: '5', column: '3' }, + { urlFormat: '{0} [{1}:{2}]', line: '5', column: '3' }, { urlFormat: '{0}",{1}', line: '5' }, { urlFormat: '{0}\',{1}', line: '5' }, { urlFormat: '{0}#{1}', line: '5' }, diff --git a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts index 2dd13565faf4d..c117ec175446a 100644 --- a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts @@ -247,7 +247,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, if (!marker) { return; } - const decoration = this._terminal.registerDecoration({ marker, layer: 'top' }); + const decoration = this._terminal.registerDecoration({ marker, width: 2, layer: 'top' }); if (!decoration) { return; } @@ -284,7 +284,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, updateLayout(this._configurationService, e); this._accessibilitySignalService.playSignal(AccessibilitySignal.terminalQuickFix); - const parentElement = (e.closest('.xterm') as HTMLElement).parentElement; + const parentElement = e.closest('.xterm')?.parentElement; if (!parentElement) { return; } diff --git a/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollContribution.ts b/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollContribution.ts index 5a1f934bcb894..c35f5b789f880 100644 --- a/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollContribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollContribution.ts @@ -103,7 +103,7 @@ export class TerminalStickyScrollContribution extends Disposable implements ITer TerminalStickyScrollOverlay, this._instance, this._xterm!, - this._instantiationService.createInstance(TerminalInstanceColorProvider, this._instance), + this._instantiationService.createInstance(TerminalInstanceColorProvider, this._instance.targetRef), this._instance.capabilities.get(TerminalCapability.CommandDetection)!, xtermCtorEventually ); diff --git a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts index 3a07a2806feda..11350dd2893dc 100644 --- a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts +++ b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts @@ -353,9 +353,8 @@ export class TerminalMessagePeek extends Disposable implements IPeekOutputRender if (prev) { prev.xterm.clearBuffer(); prev.xterm.clearSearchDecorations(); - // clearBuffer tries to retain the prompt line, but this doesn't exist for tests. - // So clear the screen (J) and move to home (H) to ensure previous data is cleaned up. - prev.xterm.write(`\x1b[2J\x1b[0;0H`); + // clearBuffer tries to retain the prompt. Reset prompt, scrolling state, etc. + prev.xterm.write(`\x1bc`); return prev; } diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts index a2e56672926d8..53e8a273940db 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts @@ -225,14 +225,7 @@ export class GettingStartedDetailsRenderer { const contents = await new Promise((resolve, reject) => { const provider = gettingStartedContentRegistry.getProvider(moduleId); if (!provider) { - // ESM-comment-begin - // require([moduleId], content => { - // resolve(content.default()); - // }); - // ESM-comment-end - // ESM-uncomment-begin reject(`Getting started: no provider registered for ${moduleId}`); - // ESM-uncomment-end } else { resolve(provider()); } diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts b/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts index 77f67a3b45142..b7ed7fdb24259 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts @@ -46,20 +46,7 @@ export async function moduleToContent(instantiationService: IInstantiationServic const provider = walkThroughContentRegistry.getProvider(query.moduleId); if (!provider) { - // ESM-comment-begin - // return new Promise((resolve, reject) => { - // require([query.moduleId], content => { - // try { - // resolve(instantiationService.invokeFunction(content.default)); - // } catch (err) { - // reject(err); - // } - // }); - // }); - // ESM-comment-end - // ESM-uncomment-begin throw new Error(`Walkthrough: no provider registered for ${query.moduleId}`); - // ESM-uncomment-end } return instantiationService.invokeFunction(provider); diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index f6bae665b130d..72527bf9ba539 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -251,7 +251,7 @@ import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL } from '../../platform/window/electron-s ], 'default': isLinux ? 'never' : 'auto', 'scope': ConfigurationScope.APPLICATION, - 'markdownDescription': localize('window.customTitleBarVisibility', "Adjust when the custom title bar should be shown. The custom title bar can be hidden when in full screen mode with `windowed`. The custom title bar can only be hidden in none full screen mode with `never` when {0} is set to `native`.", '`#window.titleBarStyle#`'), + 'markdownDescription': localize('window.customTitleBarVisibility', "Adjust when the custom title bar should be shown. The custom title bar can be hidden when in full screen mode with `windowed`. The custom title bar can only be hidden in non full screen mode with `never` when {0} is set to `native`.", '`#window.titleBarStyle#`'), }, 'window.dialogStyle': { 'type': 'string', diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index b48e9c723759a..5e7c05ca455ca 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -31,7 +31,7 @@ import { Disposable, DisposableStore, MutableDisposable, toDisposable } from '.. import { LifecyclePhase, ILifecycleService, WillShutdownEvent, ShutdownReason, BeforeShutdownErrorEvent, BeforeShutdownEvent } from '../services/lifecycle/common/lifecycle.js'; import { IWorkspaceFolderCreationData } from '../../platform/workspaces/common/workspaces.js'; import { IIntegrityService } from '../services/integrity/common/integrity.js'; -import { isWindows, isMacintosh, isCI } from '../../base/common/platform.js'; +import { isWindows, isMacintosh } from '../../base/common/platform.js'; import { IProductService } from '../../platform/product/common/productService.js'; import { INotificationService, NeverShowAgainScope, NotificationPriority, Severity } from '../../platform/notification/common/notification.js'; import { IKeybindingService } from '../../platform/keybinding/common/keybinding.js'; @@ -80,7 +80,6 @@ import { ThemeIcon } from '../../base/common/themables.js'; import { getWorkbenchContribution } from '../common/contributions.js'; import { DynamicWorkbenchSecurityConfiguration } from '../common/configuration.js'; import { nativeHoverDelegate } from '../../platform/hover/browser/hover.js'; -import { isESM } from '../../base/common/amd.js'; export class NativeWindow extends BaseWindow { @@ -708,17 +707,6 @@ export class NativeWindow extends BaseWindow { private async handleWarnings(): Promise { - // Check for cyclic dependencies - if (!isESM && typeof require.hasDependencyCycle === 'function' && require.hasDependencyCycle()) { - if (isCI) { - this.logService.error('Error: There is a dependency cycle in the AMD modules that needs to be resolved!'); - this.nativeHostService.exit(37); // running on a build machine, just exit without showing a dialog - } else { - this.dialogService.error(localize('loaderCycle', "There is a dependency cycle in the AMD modules that needs to be resolved!")); - this.nativeHostService.openDevTools(); - } - } - // After restored phase is fine for the following ones await this.lifecycleService.when(LifecyclePhase.Restored); diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index d18242bde5769..217084c9e9bbe 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -133,7 +133,7 @@ export class ApplicationConfiguration extends UserSettings { uriIdentityService: IUriIdentityService, logService: ILogService, ) { - super(userDataProfilesService.defaultProfile.settingsResource, { scopes: [ConfigurationScope.APPLICATION] }, uriIdentityService.extUri, fileService, logService); + super(userDataProfilesService.defaultProfile.settingsResource, { scopes: [ConfigurationScope.APPLICATION], skipUnregistered: true }, uriIdentityService.extUri, fileService, logService); this._register(this.onDidChange(() => this.reloadConfigurationScheduler.schedule())); this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.loadConfiguration().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50)); } diff --git a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts index ebcc88dd25d60..833dec287e066 100644 --- a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts @@ -1737,6 +1737,12 @@ suite('WorkspaceConfigurationService - Profiles', () => { assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting3'), 'defaultProfile'); })); + test('non registering setting should not be read from default profile', () => runWithFakedTimers({ useFakeTimers: true }, async () => { + await fileService.writeFile(instantiationService.get(IUserDataProfilesService).defaultProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.nonregistered": "defaultProfile" }')); + await testObject.reloadConfiguration(); + assert.strictEqual(testObject.getValue('configurationService.profiles.nonregistered'), undefined); + })); + test('initialize with custom all profiles settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue(APPLY_ALL_PROFILES_SETTING, ['configurationService.profiles.testSetting2'], ConfigurationTarget.USER_LOCAL); diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index cecd70c21af3b..7776811b727fa 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -6,7 +6,6 @@ import * as dom from '../../../../base/browser/dom.js'; import { parentOriginHash } from '../../../../base/browser/iframe.js'; import { mainWindow } from '../../../../base/browser/window.js'; -import { isESM } from '../../../../base/common/amd.js'; import { Barrier } from '../../../../base/common/async.js'; import { VSBuffer } from '../../../../base/common/buffer.js'; import { canceled, onUnexpectedError } from '../../../../base/common/errors.js'; @@ -87,7 +86,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost const suffix = `?${suffixSearchParams.toString()}`; - const iframeModulePath: AppResourcePath = `vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.${isESM ? 'esm.' : ''}html`; + const iframeModulePath: AppResourcePath = `vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html`; if (platform.isWeb) { const webEndpointUrlTemplate = this._productService.webEndpointUrlTemplate; const commit = this._productService.commit; @@ -184,13 +183,10 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost return rejectBarrier(ExtensionHostExitCode.UnexpectedError, err); } if (event.data.type === 'vscode.bootstrap.nls') { - const factoryModuleId = 'vs/base/worker/workerMain.js'; - const baseUrl = isESM ? undefined : require.toUrl(factoryModuleId).slice(0, -factoryModuleId.length); iframe.contentWindow!.postMessage({ type: event.data.type, data: { - baseUrl, - workerUrl: isESM ? FileAccess.asBrowserUri('vs/workbench/api/worker/extensionHostWorker.esm.js').toString(true) : require.toUrl(factoryModuleId), + workerUrl: FileAccess.asBrowserUri('vs/workbench/api/worker/extensionHostWorker.esm.js').toString(true), fileRoot: globalThis._VSCODE_FILE_ROOT, nls: { messages: getNLSMessages(), diff --git a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts index 0d16b8838bc24..e62e021ae8d5f 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts @@ -191,7 +191,7 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost { this._extensionHostProcess = new ExtensionHostProcess(extensionHostCreationResult.id, this._extensionHostStarter); const env = objects.mixin(processEnv, { - VSCODE_AMD_ENTRYPOINT: 'vs/workbench/api/node/extensionHostProcess', + VSCODE_ESM_ENTRYPOINT: 'vs/workbench/api/node/extensionHostProcess', VSCODE_HANDLES_UNCAUGHT_ERRORS: true }); diff --git a/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html b/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html deleted file mode 100644 index 53bc54bb5aa2a..0000000000000 --- a/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - - diff --git a/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html b/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html index a4914c6443234..21fa5056564fe 100644 --- a/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html +++ b/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html @@ -4,7 +4,7 @@ @@ -12,7 +12,7 @@ (function () { const searchParams = new URL(document.location.href).searchParams; const vscodeWebWorkerExtHostId = searchParams.get('vscodeWebWorkerExtHostId') || ''; - const name = searchParams.get('debugged') ? 'DebugWorkerExtensionHost' : 'WorkerExtensionHost'; + const name = searchParams.get('debugged') ? 'DebugExtensionHostWorker' : 'ExtensionHostWorker'; const parentOrigin = searchParams.get('parentOrigin') || window.origin; const salt = searchParams.get('salt'); @@ -93,29 +93,21 @@ workerUrl += '?vscode-coi=2'; // COEP } - // ESM-comment-begin - // const isESM = false; - // ESM-comment-end - // ESM-uncomment-begin - const isESM = true; - // ESM-uncomment-end + // In below blob code, we are using JSON.stringify to ensure the passed + // in values are not breaking our script. The values may contain string + // terminating characters (such as ' or "). const blob = new Blob([[ `/*extensionHostWorker*/`, - `globalThis.MonacoEnvironment = { baseUrl: '${baseUrl}' };`, + `globalThis.MonacoEnvironment = { baseUrl: ${JSON.stringify(baseUrl)} };`, `globalThis._VSCODE_NLS_MESSAGES = ${JSON.stringify(nlsMessages)};`, `globalThis._VSCODE_NLS_LANGUAGE = ${JSON.stringify(nlsLanguage)};`, - `globalThis._VSCODE_FILE_ROOT = '${fileRoot}';`, - isESM ? `await import('${workerUrl}');` : `importScripts('${workerUrl}');`, - isESM ? `globalThis.onmessage({ data: 'vs/workbench/api/worker/extensionHostWorker' });` : undefined, // important to start loading after the ESM async import has finished + `globalThis._VSCODE_FILE_ROOT = ${JSON.stringify(fileRoot)};`, + `await import(${JSON.stringify(workerUrl)});`, `/*extensionHostWorker*/` ].join('')], { type: 'application/javascript' }); - const worker = new Worker(URL.createObjectURL(blob), { name, type: isESM ? 'module' : undefined }); - if (!isESM) { - // Note: cannot postMessage into a worker that is ESM because imports are async - worker.postMessage('vs/workbench/api/worker/extensionHostWorker'); - } + const worker = new Worker(URL.createObjectURL(blob), { name, type: 'module' }); const nestedWorkers = new Map(); worker.onmessage = (event) => { diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts index 28f6ea57c030c..8807b7ef37087 100644 --- a/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts @@ -5,7 +5,6 @@ import * as nls from '../../../../nls.js'; import { Emitter, Event } from '../../../../base/common/event.js'; -import { isESM } from '../../../../base/common/amd.js'; import { AppResourcePath, FileAccess } from '../../../../base/common/network.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { KeymapInfo, IRawMixedKeyboardMapping, IKeymapInfo } from '../common/keymapInfo.js'; @@ -457,10 +456,7 @@ export class BrowserKeyboardMapperFactory extends BrowserKeyboardMapperFactoryBa const platform = isWindows ? 'win' : isMacintosh ? 'darwin' : 'linux'; - import(isESM ? - FileAccess.asBrowserUri(`vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.${platform}.js` satisfies AppResourcePath).path : - `vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.${platform}` - ).then((m) => { + import(FileAccess.asBrowserUri(`vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.${platform}.js` satisfies AppResourcePath).path).then((m) => { const keymapInfos: IKeymapInfo[] = m.KeyboardLayoutContribution.INSTANCE.layoutInfos; this._keymapInfos.push(...keymapInfos.map(info => (new KeymapInfo(info.layout, info.secondaryLayouts, info.mapping, info.isUserKeyboardLayout)))); this._mru = this._keymapInfos; diff --git a/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts b/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts index be4473b57cffe..dad48d9618726 100644 --- a/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts +++ b/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts @@ -21,7 +21,7 @@ import { IEditorService } from '../../editor/common/editorService.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { LRUCache } from '../../../../base/common/map.js'; import { ILogService } from '../../../../platform/log/common/log.js'; -import { canASAR } from '../../../../base/common/amd.js'; +import { canASAR } from '../../../../amdX.js'; import { createWebWorker } from '../../../../base/browser/defaultWorkerFactory.js'; import { WorkerTextModelSyncClient } from '../../../../editor/common/services/textModelSync/textModelSync.impl.js'; import { ILanguageDetectionWorker, LanguageDetectionWorkerHost } from './languageDetectionWorker.protocol.js'; @@ -71,7 +71,7 @@ export class LanguageDetectionService extends Disposable implements ILanguageDet modelService, languageService, telemetryService, - // TODO@esm: See if it's possible to bundle vscode-languagedetection + // TODO See if it's possible to bundle vscode-languagedetection useAsar ? FileAccess.asBrowserUri(`${moduleLocationAsar}/dist/lib/index.js`).toString(true) : FileAccess.asBrowserUri(`${moduleLocation}/dist/lib/index.js`).toString(true), diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index 8bc828292b109..e97874375fae9 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -422,7 +422,8 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, if (!model.isDisposed()) { visit(model.getValue(), visitor); } - return settings.length > 0 ? [{ + return settings.length > 0 ? [{ + id: model.isDisposed() ? '' : model.id, sections: [ { settings @@ -431,7 +432,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, title: '', titleRange: nullRange, range - }] : []; + } satisfies ISettingsGroup] : []; } export class WorkspaceConfigurationEditorModel extends SettingsEditorModel { @@ -844,7 +845,7 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements const metadata = this.collectMetadata(resultGroups); return resultGroups.length ? - { + { allGroups: this.settingsGroups, filteredGroups, matches, @@ -894,9 +895,10 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements filterMatches = filterMatches .map(filteredMatch => { // Fix match ranges to offset from setting start line - return { + return { setting: filteredMatch.setting, score: filteredMatch.score, + matchType: filteredMatch.matchType, matches: filteredMatch.matches && filteredMatch.matches.map(match => { return new Range( match.startLineNumber - filteredMatch.setting.range.startLineNumber, @@ -965,7 +967,7 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements } private getGroup(resultGroup: ISearchResultGroup): ISettingsGroup { - return { + return { id: resultGroup.id, range: nullRange, title: resultGroup.label, diff --git a/src/vs/workbench/services/textMate/browser/backgroundTokenization/threadedBackgroundTokenizerFactory.ts b/src/vs/workbench/services/textMate/browser/backgroundTokenization/threadedBackgroundTokenizerFactory.ts index 3113c350ac390..ea3939b7b91ad 100644 --- a/src/vs/workbench/services/textMate/browser/backgroundTokenization/threadedBackgroundTokenizerFactory.ts +++ b/src/vs/workbench/services/textMate/browser/backgroundTokenization/threadedBackgroundTokenizerFactory.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { canASAR } from '../../../../../base/common/amd.js'; +import { canASAR } from '../../../../../amdX.js'; import { DisposableStore, IDisposable, toDisposable } from '../../../../../base/common/lifecycle.js'; import { AppResourcePath, FileAccess, nodeModulesAsarPath, nodeModulesPath } from '../../../../../base/common/network.js'; import { IObservable } from '../../../../../base/common/observable.js'; diff --git a/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts b/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts index f22a15bb5996e..94a284248bf66 100644 --- a/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts +++ b/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts @@ -3,8 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { importAMDNodeModule, resolveAmdNodeModulePath } from '../../../../amdX.js'; -import { canASAR, isESM } from '../../../../base/common/amd.js'; +import { canASAR, importAMDNodeModule, resolveAmdNodeModulePath } from '../../../../amdX.js'; import * as dom from '../../../../base/browser/dom.js'; import { equals as equalArray } from '../../../../base/common/arrays.js'; import { Color } from '../../../../base/common/color.js'; @@ -372,9 +371,7 @@ export class TextMateTokenizationFeature extends Disposable implements ITextMate private async _loadVSCodeOnigurumaWASM(): Promise { if (isWeb) { - const response = await fetch(isESM - ? resolveAmdNodeModulePath('vscode-oniguruma', 'release/onig.wasm') - : FileAccess.asBrowserUri('vscode-oniguruma/../onig.wasm').toString(true)); + const response = await fetch(resolveAmdNodeModulePath('vscode-oniguruma', 'release/onig.wasm')); // Using the response directly only works if the server sets the MIME type 'application/wasm'. // Otherwise, a TypeError is thrown when using the streaming compiler. // We therefore use the non-streaming compiler :(. diff --git a/src/vs/workbench/services/textfile/common/encoding.ts b/src/vs/workbench/services/textfile/common/encoding.ts index c6933952e65c7..56a122772e737 100644 --- a/src/vs/workbench/services/textfile/common/encoding.ts +++ b/src/vs/workbench/services/textfile/common/encoding.ts @@ -8,7 +8,6 @@ import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from '../../../../ import { importAMDNodeModule } from '../../../../amdX.js'; import { CancellationTokenSource } from '../../../../base/common/cancellation.js'; import { coalesce } from '../../../../base/common/arrays.js'; -import { isESM } from '../../../../base/common/amd.js'; export const UTF8 = 'utf8'; export const UTF8_with_bom = 'utf8bom'; @@ -325,7 +324,7 @@ async function guessEncodingByBuffer(buffer: VSBuffer, candidateGuessEncodings?: // TODO@bpasero TODO@esm: this used to be `dist/jschardet.min.js`, but we are running into an issue that // https://github.com/aadsm/jschardet/pull/96 mitigates. Long-term we should just add minification // of dependencies into our build process so that we do not depend on how others are doing it. - const jschardet = await importAMDNodeModule('jschardet', isESM ? 'dist/jschardet.js' : 'dist/jschardet.min.js'); + const jschardet = await importAMDNodeModule('jschardet', 'dist/jschardet.js'); // ensure to limit buffer for guessing due to https://github.com/aadsm/jschardet/issues/53 const limitedBuffer = buffer.slice(0, AUTO_ENCODING_GUESS_MAX_BYTES); diff --git a/src/vs/workbench/services/themes/browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts index bb3c6a2ac975a..f7f38038aeb67 100644 --- a/src/vs/workbench/services/themes/browser/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts @@ -395,12 +395,14 @@ export class FileIconThemeLoader { const fonts = iconThemeDocument.fonts; const fontSizes = new Map(); if (Array.isArray(fonts)) { - const defaultFontSize = fonts[0].size || '150%'; + const defaultFontSize = this.tryNormalizeFontSize(fonts[0].size) || '150%'; fonts.forEach(font => { const src = font.src.map(l => `${asCSSUrl(resolvePath(l.path))} format('${l.format}')`).join(', '); cssRules.push(`@font-face { src: ${src}; font-family: '${font.id}'; font-weight: ${font.weight}; font-style: ${font.style}; font-display: block; }`); - if (font.size !== undefined && font.size !== defaultFontSize) { - fontSizes.set(font.id, font.size); + + const fontSize = this.tryNormalizeFontSize(font.size); + if (fontSize !== undefined && fontSize !== defaultFontSize) { + fontSizes.set(font.id, fontSize); } }); cssRules.push(`.show-file-icons .file-icon::before, .show-file-icons .folder-icon::before, .show-file-icons .rootfolder-icon::before { font-family: '${fonts[0].id}'; font-size: ${defaultFontSize}; }`); @@ -455,6 +457,27 @@ export class FileIconThemeLoader { return result; } + /** + * Try converting absolute font sizes to relative values. + * + * This allows them to be scaled nicely depending on where they are used. + */ + private tryNormalizeFontSize(size: string | undefined): string | undefined { + if (!size) { + return undefined; + } + + const defaultFontSizeInPx = 13; + + if (size.endsWith('px')) { + const value = parseInt(size, 10); + if (!isNaN(value)) { + return Math.round((value / defaultFontSizeInPx) * 100) + '%'; + } + } + + return size; + } } function handleParentFolder(key: string, selectors: string[]): string { diff --git a/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts b/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts index a8f07fb74a4f1..4d18093f41e14 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts @@ -185,7 +185,7 @@ const schema: IJSONSchema = { }, size: { type: 'string', - description: nls.localize('schema.font-size', 'The default size of the font. See https://developer.mozilla.org/en-US/docs/Web/CSS/font-size for valid values.'), + description: nls.localize('schema.font-size', 'The default size of the font. We strongly recommend using a percentage value, for example: 125%.'), pattern: fontSizeRegex } }, diff --git a/src/vs/workbench/workbench.desktop.main.css b/src/vs/workbench/workbench.desktop.main.css deleted file mode 100644 index 06ed8a197b2a3..0000000000000 --- a/src/vs/workbench/workbench.desktop.main.css +++ /dev/null @@ -1,9 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* NOTE: THIS FILE WILL BE OVERWRITTEN DURING BUILD TIME, DO NOT EDIT */ - -div.monaco.main.css { -} \ No newline at end of file diff --git a/src/vs/workbench/workbench.web.main.css b/src/vs/workbench/workbench.web.main.css deleted file mode 100644 index 3a0641938d56e..0000000000000 --- a/src/vs/workbench/workbench.web.main.css +++ /dev/null @@ -1,6 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* NOTE: THIS FILE WILL BE OVERWRITTEN DURING BUILD TIME, DO NOT EDIT */ diff --git a/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts b/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts index 75cab1bcc46ae..b89bdfbed3e25 100644 --- a/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts +++ b/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts @@ -26,7 +26,11 @@ declare module 'vscode' { /** * Code editor inline chat */ - Editor = 4 + Editor = 4, + /** + * Chat is happening in an editing session + */ + EditingSession = 5, } export class ChatRequestEditorData { diff --git a/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts b/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts index 1d71b61768a91..69061d64ffd1e 100644 --- a/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts @@ -19,6 +19,7 @@ declare module 'vscode' { export interface ConversationResponse { readonly type: 'response'; readonly message: string; + readonly result?: ChatResult; readonly references?: DocumentContextItem[]; } @@ -53,7 +54,7 @@ declare module 'vscode' { } export interface MappedEditsRequest { - readonly codeBlocks: { code: string; resource: Uri }[]; + readonly codeBlocks: { code: string; resource: Uri; markdownBeforeBlock?: string }[]; readonly conversation: (ConversationRequest | ConversationResponse)[]; // for every prior response that contains codeblocks, make sure we pass the code as well as the resources based on the reported codemapper URIs } diff --git a/src/vscode-dts/vscode.proposed.scmActionButton.d.ts b/src/vscode-dts/vscode.proposed.scmActionButton.d.ts index b035aaddc8db5..96b8b1c0e53b0 100644 --- a/src/vscode-dts/vscode.proposed.scmActionButton.d.ts +++ b/src/vscode-dts/vscode.proposed.scmActionButton.d.ts @@ -7,9 +7,8 @@ declare module 'vscode' { // https://github.com/microsoft/vscode/issues/133935 export interface SourceControlActionButton { - command: Command; + command: Command & { shortTitle?: string }; secondaryCommands?: Command[][]; - description?: string; enabled: boolean; } diff --git a/test/unit/browser/index.amd.js b/test/unit/browser/index.amd.js deleted file mode 100644 index 359a071b61e4d..0000000000000 --- a/test/unit/browser/index.amd.js +++ /dev/null @@ -1,395 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -const path = require('path'); -const glob = require('glob'); -const events = require('events'); -const mocha = require('mocha'); -const createStatsCollector = require('mocha/lib/stats-collector'); -const MochaJUnitReporter = require('mocha-junit-reporter'); -const url = require('url'); -const minimatch = require('minimatch'); -const fs = require('fs'); -const playwright = require('@playwright/test'); -const { applyReporter } = require('../reporter'); -const yaserver = require('yaserver'); -const http = require('http'); -const { randomBytes } = require('crypto'); -const minimist = require('minimist'); - -/** - * @type {{ - * run: string; - * grep: string; - * runGlob: string; - * browser: string; - * reporter: string; - * 'reporter-options': string; - * tfs: string; - * build: boolean; - * debug: boolean; - * sequential: boolean; - * help: boolean; - * }} -*/ -const args = minimist(process.argv.slice(2), { - boolean: ['build', 'debug', 'sequential', 'help'], - string: ['run', 'grep', 'runGlob', 'browser', 'reporter', 'reporter-options', 'tfs'], - default: { - build: false, - browser: ['chromium', 'firefox', 'webkit'], - reporter: process.platform === 'win32' ? 'list' : 'spec', - 'reporter-options': '' - }, - alias: { - grep: ['g', 'f'], - runGlob: ['glob', 'runGrep'], - debug: ['debug-browser'], - help: 'h' - }, - describe: { - build: 'run with build output (out-build)', - run: 'only run tests matching ', - grep: 'only run tests matching ', - debug: 'do not run browsers headless', - sequential: 'only run suites for a single browser at a time', - browser: 'browsers in which tests should run', - reporter: 'the mocha reporter', - 'reporter-options': 'the mocha reporter options', - tfs: 'tfs', - help: 'show the help' - } -}); - -if (args.help) { - console.log(`Usage: node ${process.argv[1]} [options] - -Options: ---build run with build output (out-build) ---run only run tests matching ---grep, -g, -f only run tests matching ---debug, --debug-browser do not run browsers headless ---sequential only run suites for a single browser at a time ---browser browsers in which tests should run ---reporter the mocha reporter ---reporter-options the mocha reporter options ---tfs tfs ---help, -h show the help`); - process.exit(0); -} - -const withReporter = (function () { - if (args.tfs) { - { - return (browserType, runner) => { - new mocha.reporters.Spec(runner); - new MochaJUnitReporter(runner, { - reporterOptions: { - testsuitesTitle: `${args.tfs} ${process.platform}`, - mochaFile: process.env.BUILD_ARTIFACTSTAGINGDIRECTORY ? path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${browserType}-${args.tfs.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) : undefined - } - }); - }; - } - } else { - return (_, runner) => applyReporter(runner, args); - } -})(); - -const outdir = args.build ? 'out-build' : 'out'; -const rootDir = path.resolve(__dirname, '..', '..', '..'); -const out = path.join(rootDir, `${outdir}`); - -function ensureIsArray(a) { - return Array.isArray(a) ? a : [a]; -} - -const testModules = (async function () { - - const excludeGlob = '**/{node,electron-sandbox,electron-main,electron-utility}/**/*.test.js'; - let isDefaultModules = true; - let promise; - - if (args.run) { - // use file list (--run) - isDefaultModules = false; - promise = Promise.resolve(ensureIsArray(args.run).map(file => { - file = file.replace(/^src/, 'out'); - file = file.replace(/\.ts$/, '.js'); - return path.relative(out, file); - })); - - } else { - // glob patterns (--glob) - const defaultGlob = '**/*.test.js'; - const pattern = args.runGlob || defaultGlob; - isDefaultModules = pattern === defaultGlob; - - promise = new Promise((resolve, reject) => { - glob(pattern, { cwd: out }, (err, files) => { - if (err) { - reject(err); - } else { - resolve(files); - } - }); - }); - } - - return promise.then(files => { - const modules = []; - for (const file of files) { - if (!minimatch(file, excludeGlob)) { - modules.push(file.replace(/\.js$/, '')); - - } else if (!isDefaultModules) { - console.warn(`DROPPONG ${file} because it cannot be run inside a browser`); - } - } - return modules; - }); -})(); - -function consoleLogFn(msg) { - const type = msg.type(); - const candidate = console[type]; - if (candidate) { - return candidate; - } - - if (type === 'warning') { - return console.warn; - } - - return console.log; -} - -async function createServer() { - // Demand a prefix to avoid issues with other services on the - // machine being able to access the test server. - const prefix = '/' + randomBytes(16).toString('hex'); - const serveStatic = await yaserver.createServer({ rootDir }); - - /** Handles a request for a remote method call, invoking `fn` and returning the result */ - const remoteMethod = async (req, response, fn) => { - const params = await new Promise((resolve, reject) => { - const body = []; - req.on('data', chunk => body.push(chunk)); - req.on('end', () => resolve(JSON.parse(Buffer.concat(body).toString()))); - req.on('error', reject); - }); - - const result = await fn(...params); - response.writeHead(200, { 'Content-Type': 'application/json' }); - response.end(JSON.stringify(result)); - }; - - const server = http.createServer((request, response) => { - if (!request.url?.startsWith(prefix)) { - return response.writeHead(404).end(); - } - - // rewrite the URL so the static server can handle the request correctly - request.url = request.url.slice(prefix.length); - - switch (request.url) { - case '/remoteMethod/__readFileInTests': - return remoteMethod(request, response, p => fs.promises.readFile(p, 'utf-8')); - case '/remoteMethod/__writeFileInTests': - return remoteMethod(request, response, (p, contents) => fs.promises.writeFile(p, contents)); - case '/remoteMethod/__readDirInTests': - return remoteMethod(request, response, p => fs.promises.readdir(p)); - case '/remoteMethod/__unlinkInTests': - return remoteMethod(request, response, p => fs.promises.unlink(p)); - case '/remoteMethod/__mkdirPInTests': - return remoteMethod(request, response, p => fs.promises.mkdir(p, { recursive: true })); - default: - return serveStatic.handle(request, response); - } - }); - - return new Promise((resolve, reject) => { - server.listen(0, 'localhost', () => { - resolve({ - dispose: () => server.close(), - // @ts-ignore - url: `http://localhost:${server.address().port}${prefix}` - }); - }); - server.on('error', reject); - }); -} - -async function runTestsInBrowser(testModules, browserType) { - const server = await createServer(); - const browser = await playwright[browserType].launch({ headless: !Boolean(args.debug), devtools: Boolean(args.debug) }); - const context = await browser.newContext(); - const page = await context.newPage(); - const target = new URL(server.url + '/test/unit/browser/renderer.amd.html'); - target.searchParams.set('baseUrl', url.pathToFileURL(path.join(rootDir, 'src2')).toString()); - if (args.build) { - target.searchParams.set('build', 'true'); - } - if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { - target.searchParams.set('ci', 'true'); - } - - const emitter = new events.EventEmitter(); - await page.exposeFunction('mocha_report', (type, data1, data2) => { - emitter.emit(type, data1, data2); - }); - - await page.goto(target.href); - - if (args.build) { - const nlsMessages = await fs.promises.readFile(path.join(out, 'nls.messages.json'), 'utf8'); - await page.evaluate(value => { - // when running from `out-build`, ensure to load the default - // messages file, because all `nls.localize` calls have their - // english values removed and replaced by an index. - // @ts-ignore - globalThis._VSCODE_NLS_MESSAGES = JSON.parse(value); - }, nlsMessages); - } - - page.on('console', async msg => { - consoleLogFn(msg)(msg.text(), await Promise.all(msg.args().map(async arg => await arg.jsonValue()))); - }); - - withReporter(browserType, new EchoRunner(emitter, browserType.toUpperCase())); - - // collection failures for console printing - const failingModuleIds = []; - const failingTests = []; - emitter.on('fail', (test, err) => { - failingTests.push({ title: test.fullTitle, message: err.message }); - - if (err.stack) { - const regex = /(vs\/.*\.test)\.js/; - for (const line of String(err.stack).split('\n')) { - const match = regex.exec(line); - if (match) { - failingModuleIds.push(match[1]); - return; - } - } - } - }); - - try { - // @ts-expect-error - await page.evaluate(opts => loadAndRun(opts), { - modules: testModules, - grep: args.grep, - }); - } catch (err) { - console.error(err); - } - server.dispose(); - await browser.close(); - - if (failingTests.length > 0) { - let res = `The followings tests are failing:\n - ${failingTests.map(({ title, message }) => `${title} (reason: ${message})`).join('\n - ')}`; - - if (failingModuleIds.length > 0) { - res += `\n\nTo DEBUG, open ${browserType.toUpperCase()} and navigate to ${target.href}?${failingModuleIds.map(module => `m=${module}`).join('&')}`; - } - - return `${res}\n`; - } -} - -class EchoRunner extends events.EventEmitter { - - constructor(event, title = '') { - super(); - createStatsCollector(this); - event.on('start', () => this.emit('start')); - event.on('end', () => this.emit('end')); - event.on('suite', (suite) => this.emit('suite', EchoRunner.deserializeSuite(suite, title))); - event.on('suite end', (suite) => this.emit('suite end', EchoRunner.deserializeSuite(suite, title))); - event.on('test', (test) => this.emit('test', EchoRunner.deserializeRunnable(test))); - event.on('test end', (test) => this.emit('test end', EchoRunner.deserializeRunnable(test))); - event.on('hook', (hook) => this.emit('hook', EchoRunner.deserializeRunnable(hook))); - event.on('hook end', (hook) => this.emit('hook end', EchoRunner.deserializeRunnable(hook))); - event.on('pass', (test) => this.emit('pass', EchoRunner.deserializeRunnable(test))); - event.on('fail', (test, err) => this.emit('fail', EchoRunner.deserializeRunnable(test, title), EchoRunner.deserializeError(err))); - event.on('pending', (test) => this.emit('pending', EchoRunner.deserializeRunnable(test))); - } - - static deserializeSuite(suite, titleExtra) { - return { - root: suite.root, - suites: suite.suites, - tests: suite.tests, - title: titleExtra && suite.title ? `${suite.title} - /${titleExtra}/` : suite.title, - titlePath: () => suite.titlePath, - fullTitle: () => suite.fullTitle, - timeout: () => suite.timeout, - retries: () => suite.retries, - slow: () => suite.slow, - bail: () => suite.bail - }; - } - - static deserializeRunnable(runnable, titleExtra) { - return { - title: runnable.title, - fullTitle: () => titleExtra && runnable.fullTitle ? `${runnable.fullTitle} - /${titleExtra}/` : runnable.fullTitle, - titlePath: () => runnable.titlePath, - async: runnable.async, - slow: () => runnable.slow, - speed: runnable.speed, - duration: runnable.duration, - currentRetry: () => runnable.currentRetry, - }; - } - - static deserializeError(err) { - const inspect = err.inspect; - err.inspect = () => inspect; - return err; - } -} - -testModules.then(async modules => { - - // run tests in selected browsers - const browserTypes = Array.isArray(args.browser) - ? args.browser : [args.browser]; - - let messages = []; - let didFail = false; - - try { - if (args.sequential) { - for (const browserType of browserTypes) { - messages.push(await runTestsInBrowser(modules, browserType)); - } - } else { - messages = await Promise.all(browserTypes.map(async browserType => { - return await runTestsInBrowser(modules, browserType); - })); - } - } catch (err) { - console.error(err); - process.exit(1); - } - - // aftermath - for (const msg of messages) { - if (msg) { - didFail = true; - console.log(msg); - } - } - process.exit(didFail ? 1 : 0); - -}).catch(err => { - console.error(err); -}); diff --git a/test/unit/browser/renderer.amd.html b/test/unit/browser/renderer.amd.html deleted file mode 100644 index 28e6912fcad19..0000000000000 --- a/test/unit/browser/renderer.amd.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - VSCode Tests - - - - -
- - - - - - - - - - - - - diff --git a/test/unit/electron/index.amd.js b/test/unit/electron/index.amd.js deleted file mode 100644 index a02f5613e02fb..0000000000000 --- a/test/unit/electron/index.amd.js +++ /dev/null @@ -1,350 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -// mocha disables running through electron by default. Note that this must -// come before any mocha imports. -process.env.MOCHA_COLORS = '1'; - -const { app, BrowserWindow, ipcMain, crashReporter } = require('electron'); -const product = require('../../../product.json'); -const { tmpdir } = require('os'); -const { existsSync, mkdirSync } = require('fs'); -const path = require('path'); -const mocha = require('mocha'); -const events = require('events'); -const MochaJUnitReporter = require('mocha-junit-reporter'); -const url = require('url'); -const net = require('net'); -const createStatsCollector = require('mocha/lib/stats-collector'); -const { applyReporter, importMochaReporter } = require('../reporter'); - -const minimist = require('minimist'); - -/** - * @type {{ - * grep: string; - * run: string; - * runGlob: string; - * dev: boolean; - * reporter: string; - * 'reporter-options': string; - * 'waitServer': string; - * timeout: string; - * 'crash-reporter-directory': string; - * tfs: string; - * build: boolean; - * coverage: boolean; - * coveragePath: string; - * coverageFormats: string | string[]; - * 'per-test-coverage': boolean; - * help: boolean; - * }} - */ -const args = minimist(process.argv.slice(2), { - string: ['grep', 'run', 'runGlob', 'reporter', 'reporter-options', 'waitServer', 'timeout', 'crash-reporter-directory', 'tfs', 'coveragePath', 'coverageFormats'], - boolean: ['build', 'coverage', 'help', 'dev', 'per-test-coverage'], - alias: { - 'grep': ['g', 'f'], - 'runGlob': ['glob', 'runGrep'], - 'dev': ['dev-tools', 'devTools'], - 'help': 'h' - }, - default: { - 'reporter': 'spec', - 'reporter-options': '' - } -}); - -if (args.help) { - console.log(`Usage: node ${process.argv[1]} [options] - -Options: ---grep, -g, -f only run tests matching ---run only run tests from ---runGlob, --glob, --runGrep only run tests matching ---build run with build output (out-build) ---coverage generate coverage report ---per-test-coverage generate a per-test V8 coverage report, only valid with the full-json-stream reporter ---dev, --dev-tools, --devTools open dev tools, keep window open, reuse app data ---reporter the mocha reporter (default: "spec") ---reporter-options the mocha reporter options (default: "") ---waitServer port to connect to and wait before running tests ---timeout timeout for tests ---crash-reporter-directory crash reporter directory ---tfs TFS server URL ---help, -h show the help`); - process.exit(0); -} - -let crashReporterDirectory = args['crash-reporter-directory']; -if (crashReporterDirectory) { - crashReporterDirectory = path.normalize(crashReporterDirectory); - - if (!path.isAbsolute(crashReporterDirectory)) { - console.error(`The path '${crashReporterDirectory}' specified for --crash-reporter-directory must be absolute.`); - app.exit(1); - } - - if (!existsSync(crashReporterDirectory)) { - try { - mkdirSync(crashReporterDirectory); - } catch (error) { - console.error(`The path '${crashReporterDirectory}' specified for --crash-reporter-directory does not seem to exist or cannot be created.`); - app.exit(1); - } - } - - // Crashes are stored in the crashDumps directory by default, so we - // need to change that directory to the provided one - console.log(`Found --crash-reporter-directory argument. Setting crashDumps directory to be '${crashReporterDirectory}'`); - app.setPath('crashDumps', crashReporterDirectory); - - crashReporter.start({ - companyName: 'Microsoft', - productName: process.env['VSCODE_DEV'] ? `${product.nameShort} Dev` : product.nameShort, - uploadToServer: false, - compress: true - }); -} - -if (!args.dev) { - app.setPath('userData', path.join(tmpdir(), `vscode-tests-${Date.now()}`)); -} - -function deserializeSuite(suite) { - return { - root: suite.root, - suites: suite.suites, - tests: suite.tests, - title: suite.title, - titlePath: () => suite.titlePath, - fullTitle: () => suite.fullTitle, - timeout: () => suite.timeout, - retries: () => suite.retries, - slow: () => suite.slow, - bail: () => suite.bail - }; -} - -function deserializeRunnable(runnable) { - return { - title: runnable.title, - titlePath: () => runnable.titlePath, - fullTitle: () => runnable.fullTitle, - async: runnable.async, - slow: () => runnable.slow, - speed: runnable.speed, - duration: runnable.duration, - currentRetry: () => runnable.currentRetry - }; -} - -function deserializeError(err) { - const inspect = err.inspect; - err.inspect = () => inspect; - // Unfortunately, mocha rewrites and formats err.actual/err.expected. - // This formatting is hard to reverse, so err.*JSON includes the unformatted value. - if (err.actual) { - err.actual = JSON.parse(err.actual).value; - err.actualJSON = err.actual; - } - if (err.expected) { - err.expected = JSON.parse(err.expected).value; - err.expectedJSON = err.expected; - } - return err; -} - -class IPCRunner extends events.EventEmitter { - - constructor(win) { - super(); - - this.didFail = false; - this.didEnd = false; - - ipcMain.on('start', () => this.emit('start')); - ipcMain.on('end', () => { - this.didEnd = true; - this.emit('end'); - }); - ipcMain.on('suite', (e, suite) => this.emit('suite', deserializeSuite(suite))); - ipcMain.on('suite end', (e, suite) => this.emit('suite end', deserializeSuite(suite))); - ipcMain.on('test', (e, test) => this.emit('test', deserializeRunnable(test))); - ipcMain.on('test end', (e, test) => this.emit('test end', deserializeRunnable(test))); - ipcMain.on('hook', (e, hook) => this.emit('hook', deserializeRunnable(hook))); - ipcMain.on('hook end', (e, hook) => this.emit('hook end', deserializeRunnable(hook))); - ipcMain.on('pass', (e, test) => this.emit('pass', deserializeRunnable(test))); - ipcMain.on('fail', (e, test, err) => { - this.didFail = true; - this.emit('fail', deserializeRunnable(test), deserializeError(err)); - }); - ipcMain.on('pending', (e, test) => this.emit('pending', deserializeRunnable(test))); - - ipcMain.handle('startCoverage', async () => { - win.webContents.debugger.attach(); - await win.webContents.debugger.sendCommand('Debugger.enable'); - await win.webContents.debugger.sendCommand('Profiler.enable'); - await win.webContents.debugger.sendCommand('Profiler.startPreciseCoverage', { - detailed: true, - allowTriggeredUpdates: false, - }); - }); - - const coverageScriptsReported = new Set(); - ipcMain.handle('snapshotCoverage', async (_, test) => { - const coverage = await win.webContents.debugger.sendCommand('Profiler.takePreciseCoverage'); - await Promise.all(coverage.result.map(async (r) => { - if (!coverageScriptsReported.has(r.scriptId)) { - coverageScriptsReported.add(r.scriptId); - const src = await win.webContents.debugger.sendCommand('Debugger.getScriptSource', { scriptId: r.scriptId }); - r.source = src.scriptSource; - } - })); - - if (!test) { - this.emit('coverage init', coverage); - } else { - this.emit('coverage increment', test, coverage); - } - }); - } -} - -app.on('ready', () => { - - ipcMain.on('error', (_, err) => { - if (!args.dev) { - console.error(err); - app.exit(1); - } - }); - - // We need to provide a basic `ISandboxConfiguration` - // for our preload script to function properly because - // some of our types depend on it (e.g. product.ts). - ipcMain.handle('vscode:test-vscode-window-config', async () => { - return { - product: { - version: '1.x.y', - nameShort: 'Code - OSS Dev', - nameLong: 'Code - OSS Dev', - applicationName: 'code-oss', - dataFolderName: '.vscode-oss', - urlProtocol: 'code-oss', - } - }; - }); - - // No-op since invoke the IPC as part of IIFE in the preload. - ipcMain.handle('vscode:fetchShellEnv', event => { }); - - const win = new BrowserWindow({ - height: 600, - width: 800, - show: false, - webPreferences: { - preload: path.join(__dirname, 'preload.js'), // ensure similar environment as VSCode as tests may depend on this - additionalArguments: [`--vscode-window-config=vscode:test-vscode-window-config`], - nodeIntegration: true, - contextIsolation: false, - enableWebSQL: false, - spellcheck: false - } - }); - - win.webContents.on('did-finish-load', () => { - if (args.dev) { - win.show(); - win.webContents.openDevTools(); - } - - if (args.waitServer) { - waitForServer(Number(args.waitServer)).then(sendRun); - } else { - sendRun(); - } - }); - - async function waitForServer(port) { - let timeout; - let socket; - - return new Promise(resolve => { - socket = net.connect(port, '127.0.0.1'); - socket.on('error', e => { - console.error('error connecting to waitServer', e); - resolve(undefined); - }); - - socket.on('close', () => { - resolve(undefined); - }); - - timeout = setTimeout(() => { - console.error('timed out waiting for before starting tests debugger'); - resolve(undefined); - }, 15000); - }).finally(() => { - if (socket) { - socket.end(); - } - clearTimeout(timeout); - }); - } - - function sendRun() { - win.webContents.send('run', args); - } - - win.loadURL(url.format({ pathname: path.join(__dirname, 'renderer.amd.html'), protocol: 'file:', slashes: true })); - - const runner = new IPCRunner(win); - createStatsCollector(runner); - - // Handle renderer crashes, #117068 - win.webContents.on('render-process-gone', (evt, details) => { - if (!runner.didEnd) { - console.error(`Renderer process crashed with: ${JSON.stringify(details)}`); - app.exit(1); - } - }); - - const reporters = []; - - if (args.tfs) { - reporters.push( - new mocha.reporters.Spec(runner), - new MochaJUnitReporter(runner, { - reporterOptions: { - testsuitesTitle: `${args.tfs} ${process.platform}`, - mochaFile: process.env.BUILD_ARTIFACTSTAGINGDIRECTORY ? path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${args.tfs.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) : undefined - } - }), - ); - } else { - // mocha patches symbols to use windows escape codes, but it seems like - // Electron mangles these in its output. - if (process.platform === 'win32') { - Object.assign(importMochaReporter('base').symbols, { - ok: '+', - err: 'X', - dot: '.', - }); - } - - reporters.push(applyReporter(runner, args)); - } - - if (!args.dev) { - ipcMain.on('all done', async () => { - await Promise.all(reporters.map(r => r.drain?.())); - app.exit(runner.didFail ? 1 : 0); - }); - } -}); diff --git a/test/unit/electron/renderer.amd.html b/test/unit/electron/renderer.amd.html deleted file mode 100644 index 3f022d009e0ce..0000000000000 --- a/test/unit/electron/renderer.amd.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - VSCode Tests - - - - -
- - - - - - diff --git a/test/unit/electron/renderer.amd.js b/test/unit/electron/renderer.amd.js deleted file mode 100644 index 43afa46a4c59e..0000000000000 --- a/test/unit/electron/renderer.amd.js +++ /dev/null @@ -1,475 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/*eslint-env mocha*/ - -const fs = require('fs'); -const inspector = require('inspector'); - -(function () { - const originals = {}; - let logging = false; - let withStacks = false; - - self.beginLoggingFS = (_withStacks) => { - logging = true; - withStacks = _withStacks || false; - }; - self.endLoggingFS = () => { - logging = false; - withStacks = false; - }; - - function createSpy(element, cnt) { - return function (...args) { - if (logging) { - console.log(`calling ${element}: ` + args.slice(0, cnt).join(',') + (withStacks ? (`\n` + new Error().stack.split('\n').slice(2).join('\n')) : '')); - } - return originals[element].call(this, ...args); - }; - } - - function intercept(element, cnt) { - originals[element] = fs[element]; - fs[element] = createSpy(element, cnt); - } - - [ - ['realpathSync', 1], - ['readFileSync', 1], - ['openSync', 3], - ['readSync', 1], - ['closeSync', 1], - ['readFile', 2], - ['mkdir', 1], - ['lstat', 1], - ['stat', 1], - ['watch', 1], - ['readdir', 1], - ['access', 2], - ['open', 2], - ['write', 1], - ['fdatasync', 1], - ['close', 1], - ['read', 1], - ['unlink', 1], - ['rmdir', 1], - ].forEach((element) => { - intercept(element[0], element[1]); - }); -})(); - -const { ipcRenderer } = require('electron'); -const assert = require('assert'); -const path = require('path'); -const glob = require('glob'); -const util = require('util'); -const coverage = require('../coverage'); -const { takeSnapshotAndCountClasses } = require('../analyzeSnapshot'); - -// Disabled custom inspect. See #38847 -if (util.inspect && util.inspect['defaultOptions']) { - util.inspect['defaultOptions'].customInspect = false; -} - -// VSCODE_GLOBALS: package/product.json -globalThis._VSCODE_PRODUCT_JSON = (require.__$__nodeRequire ?? require)('../../../product.json'); -globalThis._VSCODE_PACKAGE_JSON = (require.__$__nodeRequire ?? require)('../../../package.json'); - -// Test file operations that are common across platforms. Used for test infra, namely snapshot tests -Object.assign(globalThis, { - __analyzeSnapshotInTests: takeSnapshotAndCountClasses, - __readFileInTests: path => fs.promises.readFile(path, 'utf-8'), - __writeFileInTests: (path, contents) => fs.promises.writeFile(path, contents), - __readDirInTests: path => fs.promises.readdir(path), - __unlinkInTests: path => fs.promises.unlink(path), - __mkdirPInTests: path => fs.promises.mkdir(path, { recursive: true }), -}); - -const IS_CI = !!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY; -const _tests_glob = '**/test/**/*.test.js'; -let loader; -let _out; - -function initNls(opts) { - if (opts.build) { - // when running from `out-build`, ensure to load the default - // messages file, because all `nls.localize` calls have their - // english values removed and replaced by an index. - globalThis._VSCODE_NLS_MESSAGES = (require.__$__nodeRequire ?? require)(`../../../out-build/nls.messages.json`); - } -} - -function initLoader(opts) { - const outdir = opts.build ? 'out-build' : 'out'; - _out = path.join(__dirname, `../../../${outdir}`); - - const bootstrapNode = require(`../../../${outdir}/bootstrap-node`); - - // setup loader - loader = require(`${_out}/vs/loader`); - const loaderConfig = { - nodeRequire: require, - catchError: true, - baseUrl: bootstrapNode.fileUriFromPath(path.join(__dirname, '../../../src2'), { isWindows: process.platform === 'win32' }), - paths: { - 'vs': `../${outdir}/vs`, - 'lib': `../${outdir}/lib`, - 'bootstrap-fork': `../${outdir}/bootstrap-fork` - } - }; - - if (opts.coverage) { - // initialize coverage if requested - coverage.initialize(loaderConfig); - } - - loader.require.config(loaderConfig); -} - -function createCoverageReport(opts) { - if (opts.coverage) { - return coverage.createReport(opts.run || opts.runGlob, opts.coveragePath, opts.coverageFormats); - } - return Promise.resolve(undefined); -} - -function loadWorkbenchTestingUtilsModule() { - return new Promise((resolve, reject) => { - loader.require(['vs/workbench/test/common/utils'], resolve, reject); - }); -} - -async function loadModules(modules) { - for (const file of modules) { - mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_PRE_REQUIRE, globalThis, file, mocha); - const m = await new Promise((resolve, reject) => loader.require([file], resolve, reject)); - mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_REQUIRE, m, file, mocha); - mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_POST_REQUIRE, globalThis, file, mocha); - } -} - -function loadTestModules(opts) { - - if (opts.run) { - const files = Array.isArray(opts.run) ? opts.run : [opts.run]; - const modules = files.map(file => { - file = file.replace(/^src[\\/]/, ''); - return file.replace(/\.[jt]s$/, ''); - }); - return loadModules(modules); - } - - const pattern = opts.runGlob || _tests_glob; - - return new Promise((resolve, reject) => { - glob(pattern, { cwd: _out }, (err, files) => { - if (err) { - reject(err); - return; - } - const modules = files.map(file => file.replace(/\.js$/, '')); - resolve(modules); - }); - }).then(loadModules); -} - -/** @type Mocha.Test */ -let currentTest; - -async function loadTests(opts) { - - //#region Unexpected Output - - const _allowedTestOutput = [ - /The vm module of Node\.js is deprecated in the renderer process and will be removed./, - ]; - - // allow snapshot mutation messages locally - if (!IS_CI) { - _allowedTestOutput.push(/Creating new snapshot in/); - _allowedTestOutput.push(/Deleting [0-9]+ old snapshots/); - } - - const perTestCoverage = opts['per-test-coverage'] ? await PerTestCoverage.init() : undefined; - - const _allowedTestsWithOutput = new Set([ - 'creates a snapshot', // self-testing - 'validates a snapshot', // self-testing - 'cleans up old snapshots', // self-testing - 'issue #149412: VS Code hangs when bad semantic token data is received', // https://github.com/microsoft/vscode/issues/192440 - 'issue #134973: invalid semantic tokens should be handled better', // https://github.com/microsoft/vscode/issues/192440 - 'issue #148651: VSCode UI process can hang if a semantic token with negative values is returned by language service', // https://github.com/microsoft/vscode/issues/192440 - 'issue #149130: vscode freezes because of Bracket Pair Colorization', // https://github.com/microsoft/vscode/issues/192440 - 'property limits', // https://github.com/microsoft/vscode/issues/192443 - 'Error events', // https://github.com/microsoft/vscode/issues/192443 - 'fetch returns keybinding with user first if title and id matches', // - 'throw ListenerLeakError' - ]); - - const _allowedSuitesWithOutput = new Set([ - 'InteractiveChatController' - ]); - - let _testsWithUnexpectedOutput = false; - - for (const consoleFn of [console.log, console.error, console.info, console.warn, console.trace, console.debug]) { - console[consoleFn.name] = function (msg) { - if (!currentTest) { - consoleFn.apply(console, arguments); - } else if (!_allowedTestOutput.some(a => a.test(msg)) && !_allowedTestsWithOutput.has(currentTest.title) && !_allowedSuitesWithOutput.has(currentTest.parent?.title)) { - _testsWithUnexpectedOutput = true; - consoleFn.apply(console, arguments); - } - }; - } - - //#endregion - - //#region Unexpected / Loader Errors - - const _unexpectedErrors = []; - const _loaderErrors = []; - - const _allowedTestsWithUnhandledRejections = new Set([ - // Lifecycle tests - 'onWillShutdown - join with error is handled', - 'onBeforeShutdown - veto with error is treated as veto', - 'onBeforeShutdown - final veto with error is treated as veto', - // Search tests - 'Search Model: Search reports timed telemetry on search when error is called' - ]); - - loader.require.config({ - onError(err) { - _loaderErrors.push(err); - console.error(err); - } - }); - - loader.require(['vs/base/common/errors'], function (errors) { - - const onUnexpectedError = function (err) { - if (err.name === 'Canceled') { - return; // ignore canceled errors that are common - } - - let stack = (err ? err.stack : null); - if (!stack) { - stack = new Error().stack; - } - - _unexpectedErrors.push((err && err.message ? err.message : err) + '\n' + stack); - }; - - process.on('uncaughtException', error => onUnexpectedError(error)); - process.on('unhandledRejection', (reason, promise) => { - onUnexpectedError(reason); - promise.catch(() => { }); - }); - window.addEventListener('unhandledrejection', event => { - event.preventDefault(); // Do not log to test output, we show an error later when test ends - event.stopPropagation(); - - if (!_allowedTestsWithUnhandledRejections.has(currentTest.title)) { - onUnexpectedError(event.reason); - } - }); - - errors.setUnexpectedErrorHandler(err => unexpectedErrorHandler(err)); - }); - - //#endregion - - return loadWorkbenchTestingUtilsModule().then((workbenchTestingModule) => { - const assertCleanState = workbenchTestingModule.assertCleanState; - - suite('Tests are using suiteSetup and setup correctly', () => { - test('assertCleanState - check that registries are clean at the start of test running', () => { - assertCleanState(); - }); - }); - - setup(async () => { - await perTestCoverage?.startTest(); - }); - - teardown(async () => { - await perTestCoverage?.finishTest(currentTest.file, currentTest.fullTitle()); - - // should not have unexpected output - // if (_testsWithUnexpectedOutput && !opts.dev) { - // assert.ok(false, 'Error: Unexpected console output in test run. Please ensure no console.[log|error|info|warn] usage in tests or runtime errors.'); - // } - - // should not have unexpected errors - const errors = _unexpectedErrors.concat(_loaderErrors); - if (errors.length) { - for (const error of errors) { - console.error(`Error: Test run should not have unexpected errors:\n${error}`); - } - assert.ok(false, 'Error: Test run should not have unexpected errors.'); - } - }); - - suiteTeardown(() => { // intentionally not in teardown because some tests only cleanup in suiteTeardown - - // should have cleaned up in registries - assertCleanState(); - }); - - return loadTestModules(opts); - }); -} - -function serializeSuite(suite) { - return { - root: suite.root, - suites: suite.suites.map(serializeSuite), - tests: suite.tests.map(serializeRunnable), - title: suite.title, - fullTitle: suite.fullTitle(), - titlePath: suite.titlePath(), - timeout: suite.timeout(), - retries: suite.retries(), - slow: suite.slow(), - bail: suite.bail() - }; -} - -function serializeRunnable(runnable) { - return { - title: runnable.title, - fullTitle: runnable.fullTitle(), - titlePath: runnable.titlePath(), - async: runnable.async, - slow: runnable.slow(), - speed: runnable.speed, - duration: runnable.duration - }; -} - -function serializeError(err) { - return { - message: err.message, - stack: err.stack, - snapshotPath: err.snapshotPath, - actual: safeStringify({ value: err.actual }), - expected: safeStringify({ value: err.expected }), - uncaught: err.uncaught, - showDiff: err.showDiff, - inspect: typeof err.inspect === 'function' ? err.inspect() : '' - }; -} - -function safeStringify(obj) { - const seen = new Set(); - return JSON.stringify(obj, (key, value) => { - if (value === undefined) { - return '[undefined]'; - } - - if (isObject(value) || Array.isArray(value)) { - if (seen.has(value)) { - return '[Circular]'; - } else { - seen.add(value); - } - } - return value; - }); -} - -function isObject(obj) { - // The method can't do a type cast since there are type (like strings) which - // are subclasses of any put not positvely matched by the function. Hence type - // narrowing results in wrong results. - return typeof obj === 'object' - && obj !== null - && !Array.isArray(obj) - && !(obj instanceof RegExp) - && !(obj instanceof Date); -} - -class IPCReporter { - - constructor(runner) { - runner.on('start', () => ipcRenderer.send('start')); - runner.on('end', () => ipcRenderer.send('end')); - runner.on('suite', suite => ipcRenderer.send('suite', serializeSuite(suite))); - runner.on('suite end', suite => ipcRenderer.send('suite end', serializeSuite(suite))); - runner.on('test', test => ipcRenderer.send('test', serializeRunnable(test))); - runner.on('test end', test => ipcRenderer.send('test end', serializeRunnable(test))); - runner.on('hook', hook => ipcRenderer.send('hook', serializeRunnable(hook))); - runner.on('hook end', hook => ipcRenderer.send('hook end', serializeRunnable(hook))); - runner.on('pass', test => ipcRenderer.send('pass', serializeRunnable(test))); - runner.on('fail', (test, err) => ipcRenderer.send('fail', serializeRunnable(test), serializeError(err))); - runner.on('pending', test => ipcRenderer.send('pending', serializeRunnable(test))); - } -} - -function runTests(opts) { - // this *must* come before loadTests, or it doesn't work. - if (opts.timeout !== undefined) { - mocha.timeout(opts.timeout); - } - - return loadTests(opts).then(() => { - - if (opts.grep) { - mocha.grep(opts.grep); - } - - if (!opts.dev) { - mocha.reporter(IPCReporter); - } - - const runner = mocha.run(() => { - createCoverageReport(opts).then(() => { - ipcRenderer.send('all done'); - }); - }); - - runner.on('test', test => currentTest = test); - - if (opts.dev) { - runner.on('fail', (test, err) => { - console.error(test.fullTitle()); - console.error(err.stack); - }); - } - }); -} - -ipcRenderer.on('run', (e, opts) => { - initNls(opts); - initLoader(opts); - runTests(opts).catch(err => { - if (typeof err !== 'string') { - err = JSON.stringify(err); - } - - console.error(err); - ipcRenderer.send('error', err); - }); -}); - -class PerTestCoverage { - static async init() { - await ipcRenderer.invoke('startCoverage'); - return new PerTestCoverage(); - } - - async startTest() { - if (!this.didInit) { - this.didInit = true; - await ipcRenderer.invoke('snapshotCoverage'); - } - } - - async finishTest(file, fullTitle) { - await ipcRenderer.invoke('snapshotCoverage', { file, fullTitle }); - } -} diff --git a/test/unit/node/index.amd.js b/test/unit/node/index.amd.js deleted file mode 100644 index f4ca72bde566e..0000000000000 --- a/test/unit/node/index.amd.js +++ /dev/null @@ -1,238 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -process.env.MOCHA_COLORS = '1'; // Force colors (note that this must come before any mocha imports) - -const assert = require('assert'); -const Mocha = require('mocha'); -const path = require('path'); -const fs = require('fs'); -const glob = require('glob'); -const minimatch = require('minimatch'); -const coverage = require('../coverage'); -const minimist = require('minimist'); -const { takeSnapshotAndCountClasses } = require('../analyzeSnapshot'); - -/** - * @type {{ build: boolean; run: string; runGlob: string; coverage: boolean; help: boolean; coverageFormats: string | string[]; coveragePath: string; }} - */ -const args = minimist(process.argv.slice(2), { - boolean: ['build', 'coverage', 'help'], - string: ['run', 'coveragePath', 'coverageFormats'], - alias: { - h: 'help' - }, - default: { - build: false, - coverage: false, - help: false - }, - description: { - build: 'Run from out-build', - run: 'Run a single file', - coverage: 'Generate a coverage report', - coveragePath: 'Path to coverage report to generate', - coverageFormats: 'Coverage formats to generate', - help: 'Show help' - } -}); - -if (args.help) { - console.log(`Usage: node test/unit/node/index [options] - -Options: ---build Run from out-build ---run Run a single file ---coverage Generate a coverage report ---help Show help`); - process.exit(0); -} - -const TEST_GLOB = '**/test/**/*.test.js'; - -const excludeGlobs = [ - '**/{browser,electron-sandbox,electron-main,electron-utility}/**/*.test.js', - '**/vs/platform/environment/test/node/nativeModules.test.js', // native modules are compiled against Electron and this test would fail with node.js - '**/vs/base/parts/storage/test/node/storage.test.js', // same as above, due to direct dependency to sqlite native module - '**/vs/workbench/contrib/testing/test/**' // flaky (https://github.com/microsoft/vscode/issues/137853) -]; - -const REPO_ROOT = path.join(__dirname, '../../../'); -const out = args.build ? 'out-build' : 'out'; -const loader = require(`../../../${out}/vs/loader`); -const src = path.join(REPO_ROOT, out); - -//@ts-ignore -const majorRequiredNodeVersion = `v${/^target="(.*)"$/m.exec(fs.readFileSync(path.join(REPO_ROOT, 'remote', '.npmrc'), 'utf8'))[1]}`.substring(0, 3); -const currentMajorNodeVersion = process.version.substring(0, 3); -if (majorRequiredNodeVersion !== currentMajorNodeVersion) { - console.error(`node.js unit tests require a major node.js version of ${majorRequiredNodeVersion} (your version is: ${currentMajorNodeVersion})`); - process.exit(1); -} - -function main() { - - // VSCODE_GLOBALS: package/product.json - globalThis._VSCODE_PRODUCT_JSON = require(`${REPO_ROOT}/product.json`); - globalThis._VSCODE_PACKAGE_JSON = require(`${REPO_ROOT}/package.json`); - - if (args.build) { - // when running from `out-build`, ensure to load the default - // messages file, because all `nls.localize` calls have their - // english values removed and replaced by an index. - globalThis._VSCODE_NLS_MESSAGES = require(`../../../${out}/nls.messages.json`); - } - - // Test file operations that are common across platforms. Used for test infra, namely snapshot tests - Object.assign(globalThis, { - __analyzeSnapshotInTests: takeSnapshotAndCountClasses, - __readFileInTests: (/** @type {string} */ path) => fs.promises.readFile(path, 'utf-8'), - __writeFileInTests: (/** @type {string} */ path, /** @type {BufferEncoding} */ contents) => fs.promises.writeFile(path, contents), - __readDirInTests: (/** @type {string} */ path) => fs.promises.readdir(path), - __unlinkInTests: (/** @type {string} */ path) => fs.promises.unlink(path), - __mkdirPInTests: (/** @type {string} */ path) => fs.promises.mkdir(path, { recursive: true }), - }); - - process.on('uncaughtException', function (e) { - console.error(e.stack || e); - }); - - const bootstrapNode = require(`../../../${out}/bootstrap-node`); - - const loaderConfig = { - nodeRequire: require, - baseUrl: bootstrapNode.fileUriFromPath(src, { isWindows: process.platform === 'win32' }), - catchError: true - }; - - if (args.coverage) { - coverage.initialize(loaderConfig); - - process.on('exit', function (code) { - if (code !== 0) { - return; - } - coverage.createReport(args.run || args.runGlob, args.coveragePath, args.coverageFormats); - }); - } - - loader.config(loaderConfig); - - let didErr = false; - const write = process.stderr.write; - process.stderr.write = function (...args) { - didErr = didErr || !!args[0]; - return write.apply(process.stderr, args); - }; - - - const runner = new Mocha({ - ui: 'tdd' - }); - - /** - * @param {string[]} modules - */ - async function loadModules(modules) { - for (const file of modules) { - runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_PRE_REQUIRE, globalThis, file, runner); - const m = await new Promise((resolve, reject) => loader([file], resolve, reject)); - runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_REQUIRE, m, file, runner); - runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_POST_REQUIRE, globalThis, file, runner); - } - } - - /** @type { null|((callback:(err:any)=>void)=>void) } */ - let loadFunc = null; - - if (args.runGlob) { - loadFunc = (cb) => { - const doRun = /** @param {string[]} tests */(tests) => { - const modulesToLoad = tests.map(test => { - if (path.isAbsolute(test)) { - test = path.relative(src, path.resolve(test)); - } - - return test.replace(/(\.js)|(\.d\.ts)|(\.js\.map)$/, ''); - }); - loadModules(modulesToLoad).then(() => cb(null), cb); - }; - - glob(args.runGlob, { cwd: src }, function (err, files) { doRun(files); }); - }; - } else if (args.run) { - const tests = (typeof args.run === 'string') ? [args.run] : args.run; - const modulesToLoad = tests.map(function (test) { - test = test.replace(/^src/, 'out'); - test = test.replace(/\.ts$/, '.js'); - return path.relative(src, path.resolve(test)).replace(/(\.js)|(\.js\.map)$/, '').replace(/\\/g, '/'); - }); - loadFunc = (cb) => { - loadModules(modulesToLoad).then(() => cb(null), cb); - }; - } else { - loadFunc = (cb) => { - glob(TEST_GLOB, { cwd: src }, function (err, files) { - /** @type {string[]} */ - const modules = []; - for (const file of files) { - if (!excludeGlobs.some(excludeGlob => minimatch(file, excludeGlob))) { - modules.push(file.replace(/\.js$/, '')); - } - } - loadModules(modules).then(() => cb(null), cb); - }); - }; - } - - loadFunc(function (err) { - if (err) { - console.error(err); - return process.exit(1); - } - - process.stderr.write = write; - - if (!args.run && !args.runGlob) { - // set up last test - Mocha.suite('Loader', function () { - test('should not explode while loading', function () { - assert.ok(!didErr, `should not explode while loading: ${didErr}`); - }); - }); - } - - // report failing test for every unexpected error during any of the tests - const unexpectedErrors = []; - Mocha.suite('Errors', function () { - test('should not have unexpected errors in tests', function () { - if (unexpectedErrors.length) { - unexpectedErrors.forEach(function (stack) { - console.error(''); - console.error(stack); - }); - - assert.ok(false); - } - }); - }); - - // replace the default unexpected error handler to be useful during tests - loader(['vs/base/common/errors'], function (errors) { - errors.setUnexpectedErrorHandler(function (err) { - const stack = (err && err.stack) || (new Error().stack); - unexpectedErrors.push((err && err.message ? err.message : err) + '\n' + stack); - }); - - // fire up mocha - runner.run(failures => process.exit(failures ? 1 : 0)); - }); - }); -} - -main();