diff --git a/.github/classifier.json b/.github/classifier.json index 8b5b7941d05..33c179d3237 100644 --- a/.github/classifier.json +++ b/.github/classifier.json @@ -1,5 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/microsoft/vscode-github-triage-actions/master/classifier-deep/apply/apply-labels/deep-classifier-config.schema.json", + "vacation": ["joaomoreno"], "assignees": { "JacksonKearl": {"accuracy": 0.5} }, @@ -119,7 +120,7 @@ "remote-explorer": {"assign": ["alexr00"]}, "rename": {"assign": ["jrieken"]}, "scm": {"assign": ["joaomoreno"]}, - "screencast-mode": {"assign": ["joaomoreno"]}, + "screencast-mode": {"assign": ["lszomoru"]}, "search": {"assign": ["roblourens"]}, "search-editor": {"assign": ["JacksonKearl"]}, "search-replace": {"assign": ["sandy081"]}, @@ -133,7 +134,7 @@ "snippets": {"assign": ["jrieken"]}, "splitview": {"assign": ["joaomoreno"]}, "suggest": {"assign": ["jrieken"]}, - "tasks": {"assign": ["alexr00"]}, + "tasks": {"assign": ["alexr00"], "accuracy": 0.85}, "telemetry": {"assign": []}, "themes": {"assign": ["aeschli"]}, "timeline": {"assign": ["eamodio"]}, diff --git a/.github/commands.json b/.github/commands.json index 7d93e109e10..1b2bc516842 100644 --- a/.github/commands.json +++ b/.github/commands.json @@ -297,7 +297,7 @@ ], "action": "close", "addLabel": "*caused-by-extension", - "comment": "It looks like this is caused by the Powershell extension. Please file it with the repository [here](https://github.com/PowerShell/vscode-powershell). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + "comment": "It looks like this is caused by the PowerShell extension. Please file it with the repository [here](https://github.com/PowerShell/vscode-powershell). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" }, { "type": "comment", diff --git a/.github/workflows/author-verified.yml b/.github/workflows/author-verified.yml index 7114f351353..167f27a5490 100644 --- a/.github/workflows/author-verified.yml +++ b/.github/workflows/author-verified.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'microsoft/vscode-github-triage-actions' - ref: v31 + ref: v34 path: ./actions - name: Install Actions if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'author-verification-requested') diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml index 7036a4937d4..61c82aa73ca 100644 --- a/.github/workflows/commands.yml +++ b/.github/workflows/commands.yml @@ -13,7 +13,7 @@ jobs: with: repository: 'microsoft/vscode-github-triage-actions' path: ./actions - ref: v31 + ref: v34 - name: Install Actions run: npm install --production --prefix ./actions - name: Run Commands diff --git a/.github/workflows/deep-classifier-monitor.yml b/.github/workflows/deep-classifier-monitor.yml index 7aa6d9de22f..9425ae0f1f2 100644 --- a/.github/workflows/deep-classifier-monitor.yml +++ b/.github/workflows/deep-classifier-monitor.yml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'microsoft/vscode-github-triage-actions' - ref: v31 + ref: v34 path: ./actions - name: Install Actions run: npm install --production --prefix ./actions diff --git a/.github/workflows/deep-classifier-runner.yml b/.github/workflows/deep-classifier-runner.yml index 4ac237e5f83..2f598745e49 100644 --- a/.github/workflows/deep-classifier-runner.yml +++ b/.github/workflows/deep-classifier-runner.yml @@ -1,7 +1,7 @@ name: "Deep Classifier: Runner" on: schedule: - - cron: 0/30 * * * * + - cron: 0 * * * * repository_dispatch: types: [trigger-deep-classifier-runner] @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'microsoft/vscode-github-triage-actions' - ref: v31 + ref: v34 path: ./actions - name: Install Actions run: npm install --production --prefix ./actions @@ -24,7 +24,7 @@ jobs: uses: ./actions/classifier-deep/apply/fetch-sources with: # slightly overlapping to protect against issues slipping through the cracks if a run is delayed - from: 40 + from: 80 until: 5 configPath: classifier blobContainerName: vscode-issue-classifier diff --git a/.github/workflows/deep-classifier-scraper.yml b/.github/workflows/deep-classifier-scraper.yml index c93f2b5352f..b9cb6ec3cd3 100644 --- a/.github/workflows/deep-classifier-scraper.yml +++ b/.github/workflows/deep-classifier-scraper.yml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'microsoft/vscode-github-triage-actions' - ref: v31 + ref: v34 path: ./actions - name: Install Actions run: npm install --production --prefix ./actions diff --git a/.github/workflows/english-please.yml b/.github/workflows/english-please.yml index 1ecc532ce88..fdfd548291d 100644 --- a/.github/workflows/english-please.yml +++ b/.github/workflows/english-please.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'microsoft/vscode-github-triage-actions' - ref: v31 + ref: v34 path: ./actions - name: Install Actions if: contains(github.event.issue.labels.*.name, '*english-please') diff --git a/.github/workflows/feature-request.yml b/.github/workflows/feature-request.yml index cdd65c77202..12af1423506 100644 --- a/.github/workflows/feature-request.yml +++ b/.github/workflows/feature-request.yml @@ -18,7 +18,7 @@ jobs: with: repository: 'microsoft/vscode-github-triage-actions' path: ./actions - ref: v31 + ref: v34 - name: Install Actions if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request') run: npm install --production --prefix ./actions diff --git a/.github/workflows/latest-release-monitor.yml b/.github/workflows/latest-release-monitor.yml index a00d3554147..a5777e3a7f1 100644 --- a/.github/workflows/latest-release-monitor.yml +++ b/.github/workflows/latest-release-monitor.yml @@ -14,7 +14,7 @@ jobs: with: repository: 'microsoft/vscode-github-triage-actions' path: ./actions - ref: v31 + ref: v34 - name: Install Actions run: npm install --production --prefix ./actions - name: Install Storage Module diff --git a/.github/workflows/locker.yml b/.github/workflows/locker.yml index d805f6a6428..64ac30d3717 100644 --- a/.github/workflows/locker.yml +++ b/.github/workflows/locker.yml @@ -14,7 +14,7 @@ jobs: with: repository: 'microsoft/vscode-github-triage-actions' path: ./actions - ref: v31 + ref: v34 - name: Install Actions run: npm install --production --prefix ./actions - name: Run Locker diff --git a/.github/workflows/needs-more-info-closer.yml b/.github/workflows/needs-more-info-closer.yml index d143dec9536..018caf24fe0 100644 --- a/.github/workflows/needs-more-info-closer.yml +++ b/.github/workflows/needs-more-info-closer.yml @@ -14,16 +14,17 @@ jobs: with: repository: 'microsoft/vscode-github-triage-actions' path: ./actions - ref: v31 + ref: v34 - name: Install Actions run: npm install --production --prefix ./actions - name: Run Needs More Info Closer uses: ./actions/needs-more-info-closer with: appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} + token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} label: needs more info closeDays: 7 additionalTeam: "cleidigh|usernamehw|gjsjohnmurray|IllusionMH" closeComment: "This issue has been closed automatically because it needs more information and has not had recent activity. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" - pingDays: 100 + pingDays: 80 pingComment: "Hey @${assignee}, this issue might need further attention.\n\n@${author}, you can help us out by closing this issue if the problem no longer exists, or adding more information." diff --git a/.github/workflows/on-label.yml b/.github/workflows/on-label.yml index 97c8ee18e8e..446c041ebd3 100644 --- a/.github/workflows/on-label.yml +++ b/.github/workflows/on-label.yml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'microsoft/vscode-github-triage-actions' - ref: v31 + ref: v34 path: ./actions - name: Install Actions run: npm install --production --prefix ./actions diff --git a/.github/workflows/on-open.yml b/.github/workflows/on-open.yml index e8c41404d99..e4f0434dbdc 100644 --- a/.github/workflows/on-open.yml +++ b/.github/workflows/on-open.yml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'microsoft/vscode-github-triage-actions' - ref: v31 + ref: v34 path: ./actions - name: Install Actions run: npm install --production --prefix ./actions diff --git a/.github/workflows/release-pipeline-labeler.yml b/.github/workflows/release-pipeline-labeler.yml index bc45221133f..14f74f581dd 100644 --- a/.github/workflows/release-pipeline-labeler.yml +++ b/.github/workflows/release-pipeline-labeler.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'microsoft/vscode-github-triage-actions' - ref: v31 + ref: v34 path: ./actions - name: Checkout Repo if: github.event_name != 'issues' diff --git a/.github/workflows/rich-navigation.yml b/.github/workflows/rich-navigation.yml index d1ac9f09921..185c770dd0f 100644 --- a/.github/workflows/rich-navigation.yml +++ b/.github/workflows/rich-navigation.yml @@ -16,7 +16,11 @@ jobs: run: yarn --frozen-lockfile env: CHILD_CONCURRENCY: 1 - - uses: microsoft/RichCodeNavIndexer@master + - name: Install .NET Core 2.2 + uses: actions/setup-dotnet@v1.5.0 + with: + dotnet-version: 2.2 + - uses: microsoft/RichCodeNavIndexer@v0.1 with: languages: typescript repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-plan-item-validator.yml b/.github/workflows/test-plan-item-validator.yml index 2dbf0e45871..4365afa03e5 100644 --- a/.github/workflows/test-plan-item-validator.yml +++ b/.github/workflows/test-plan-item-validator.yml @@ -14,7 +14,7 @@ jobs: with: repository: 'microsoft/vscode-github-triage-actions' path: ./actions - ref: v31 + ref: v34 - name: Install Actions if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item') run: npm install --production --prefix ./actions diff --git a/.gitignore b/.gitignore index e73dd4d9e8c..0fe46b6eadc 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ out-vscode-reh-web-min/ out-vscode-reh-web-pkg/ out-vscode-web/ out-vscode-web-min/ +out-vscode-web-pkg/ src/vs/server resources/server build/node_modules diff --git a/.vscode/launch.json b/.vscode/launch.json index 14bceb63786..33801a60ee3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -176,6 +176,24 @@ "order": 6 } }, + { + "type": "extensionHost", + "request": "launch", + "name": "VS Code Custom Editor Tests", + "runtimeExecutable": "${execPath}", + "args": [ + "${workspaceFolder}/extensions/vscode-custom-editor-tests/test-workspace", + "--extensionDevelopmentPath=${workspaceFolder}/extensions/vscode-custom-editor-tests", + "--extensionTestsPath=${workspaceFolder}/extensions/vscode-custom-editor-tests/out/test" + ], + "outFiles": [ + "${workspaceFolder}/out/**/*.js" + ], + "presentation": { + "group": "5_tests", + "order": 6 + } + }, { "type": "chrome", "request": "attach", @@ -198,29 +216,32 @@ "port": 9222, "timeout": 20000, "env": { - "VSCODE_EXTHOST_WILL_SEND_SOCKET": null + "VSCODE_EXTHOST_WILL_SEND_SOCKET": null, + "VSCODE_SKIP_PRELAUNCH": "1" }, "cleanUp": "wholeBrowser", - "breakOnLoad": false, "urlFilter": "*workbench.html*", "runtimeArgs": [ "--inspect=5875", "--no-cached-data", ], "webRoot": "${workspaceFolder}", - // Settings for js-debug: + "cascadeTerminateToConfigurations": [ + "Attach to Extension Host" + ], "userDataDir": false, "pauseForSourceMap": false, "outFiles": [ "${workspaceFolder}/out/**/*.js" ], - "browserLaunchLocation": "workspace" + "browserLaunchLocation": "workspace", + "preLaunchTask": "Ensure Prelaunch Dependencies", }, { "type": "node", "request": "launch", "name": "VS Code (Web)", - "program": "${workspaceFolder}/resources/serverless/code-web.js", + "program": "${workspaceFolder}/resources/web/code-web.js", "presentation": { "group": "0_vscode", "order": 2 @@ -417,6 +438,7 @@ "Attach to Extension Host", "Attach to Shared Process", ], + "preLaunchTask": "Ensure Prelaunch Dependencies", "presentation": { "group": "0_vscode", "order": 1 diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues index f36bb397581..ad2d028465e 100644 --- a/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -8,7 +8,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"July 2020\"", + "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"August 2020\"", "editable": true }, { diff --git a/.vscode/notebooks/inbox.github-issues b/.vscode/notebooks/inbox.github-issues index 8931e7b0b3b..e2e9e8a1cbb 100644 --- a/.vscode/notebooks/inbox.github-issues +++ b/.vscode/notebooks/inbox.github-issues @@ -11,6 +11,18 @@ "value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item ", "editable": true }, + { + "kind": 1, + "language": "markdown", + "value": "## Inbox tracking and Issue triage", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "New issues or pull requests submitted by the community are initially triaged by an [automatic classification bot](https://github.com/microsoft/vscode-github-triage-actions/tree/master/classifier-deep). Issues that the bot does not correctly triage are then triaged by a team member. The team rotates the inbox tracker on a weekly basis.\n\nA [mirror](https://github.com/JacksonKearl/testissues/issues) of the VS Code issue stream is available with details about how the bot classifies issues, including feature-area classifications and confidence ratings. Per-category confidence thresholds and feature-area ownership data is maintained in [.github/classifier.json](https://github.com/microsoft/vscode/blob/master/.github/classifier.json). \n\nšŸ’” The bot is being run through a GitHub action that runs every 30 minutes. Give the bot the opportunity to classify an issue before doing it manually.\n\n### Inbox Tracking\n\nThe inbox tracker is responsible for the [global inbox](https://github.com/Microsoft/vscode/issues?utf8=%E2%9C%93&q=is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Atestplan-item+-label%3Aplan-item) containing all **open issues and pull requests** that\n- are neither **feature requests** nor **test plan items** nor **plan items** and\n- have **no owner assignment**.\n\nThe **inbox tracker** may perform any step described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) but its main responsibility is to route issues to the actual feature area owner.\n\nFeature area owners track the **feature area inbox** containing all **open issues and pull requests** that\n- are personally assigned to them and are not assigned to any milestone\n- are labeled with their feature area label and are not assigned to any milestone.\nThis secondary triage may involve any of the steps described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) and results in a fully triaged or closed issue.\n\nThe [github triage extension](https://github.com/microsoft/vscode-github-triage-extension) can be used to assist with triaging — it provides a \"Command Palette\"-style list of triaging actions like assignment, labeling, and triggers for various bot actions.", + "editable": true + }, { "kind": 1, "language": "markdown", @@ -32,7 +44,7 @@ { "kind": 2, "language": "github-issues", - "value": "$inbox", - "editable": false + "value": "$inbox -label:emmet", + "editable": true } ] \ No newline at end of file diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index dc6d33365d7..d1452276f6e 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -8,7 +8,7 @@ { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks\n\n// current milestone name\n$milestone=milestone:\"June 2020\"", + "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks\n\n// current milestone name\n$milestone=milestone:\"August 2020\"", "editable": true }, { diff --git a/.vscode/notebooks/verification.github-issues b/.vscode/notebooks/verification.github-issues index 6f32df8e077..79f7f8a5c0e 100644 --- a/.vscode/notebooks/verification.github-issues +++ b/.vscode/notebooks/verification.github-issues @@ -14,7 +14,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks \n$milestone=milestone:\"June 2020\"", + "value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks \n$milestone=milestone:\"July 2020\"", "editable": true }, { @@ -44,7 +44,8 @@ { "kind": 1, "language": "markdown", - "value": "### All" + "value": "### All", + "editable": true }, { "kind": 2, diff --git a/.vscode/searches/es6.code-search b/.vscode/searches/es6.code-search index 9cf8cf0b264..6ab0d14c5ac 100644 --- a/.vscode/searches/es6.code-search +++ b/.vscode/searches/es6.code-search @@ -34,11 +34,11 @@ src/vs/base/common/arrays.ts: 420 */ 421 export function first(array: ReadonlyArray, fn: (item: T) => boolean, notFoundValue: T): T; - 569 - 570 /** - 571: * @deprecated ES6: use `Array.find` - 572 */ - 573 export function find(arr: ArrayLike, predicate: (value: T, index: number, arr: ArrayLike) => any): T | undefined { + 568 + 569 /** + 570: * @deprecated ES6: use `Array.find` + 571 */ + 572 export function find(arr: ArrayLike, predicate: (value: T, index: number, arr: ArrayLike) => any): T | undefined { src/vs/base/common/objects.ts: 115 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 213183bc072..f2857f8a280 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -186,6 +186,14 @@ "source": "eslint", "base": "$eslint-stylish" } - } + }, + { + "type": "shell", + "command": "node build/lib/preLaunch.js", + "label": "Ensure Prelaunch Dependencies", + "presentation": { + "reveal": "silent" + } + }, ] } diff --git a/.yarnrc b/.yarnrc index 5119ded1027..68cb12c1284 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "9.1.0" +target "9.2.0" runtime "electron" diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 0388430595d..ac17c9eaa64 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -61,9 +61,9 @@ This project incorporates components from the projects listed below. The origina 54. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) 55. TypeScript-TmLanguage version 0.1.8 (https://github.com/Microsoft/TypeScript-TmLanguage) 56. TypeScript-TmLanguage version 1.0.0 (https://github.com/Microsoft/TypeScript-TmLanguage) -57. Unicode version 12.0.0 (http://www.unicode.org/) +57. Unicode version 12.0.0 (https://home.unicode.org/) 58. vscode-codicons version 0.0.1 (https://github.com/microsoft/vscode-codicons) -59. vscode-logfile-highlighter version 2.6.0 (https://github.com/emilast/vscode-logfile-highlighter) +59. vscode-logfile-highlighter version 2.8.0 (https://github.com/emilast/vscode-logfile-highlighter) 60. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) 61. Web Background Synchronization (https://github.com/WICG/BackgroundSync) diff --git a/build/azure-pipelines/darwin/continuous-build-darwin.yml b/build/azure-pipelines/darwin/continuous-build-darwin.yml index eccd74db1c6..631b9af7f10 100644 --- a/build/azure-pipelines/darwin/continuous-build-darwin.yml +++ b/build/azure-pipelines/darwin/continuous-build-darwin.yml @@ -50,7 +50,7 @@ steps: displayName: Run Unit Tests (Electron) - script: | - yarn test-browser --browser chromium --browser webkit --browser firefox + yarn test-browser --browser chromium --browser webkit --browser firefox --tfs "Browser Unit Tests" displayName: Run Unit Tests (Browser) - script: | diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 7505e5ba9da..3b186bb1136 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -101,7 +101,7 @@ steps: - script: | set -e - yarn test-browser --build --browser chromium --browser webkit --browser firefox + yarn test-browser --build --browser chromium --browser webkit --browser firefox --tfs "Browser Unit Tests" displayName: Run unit tests (Browser) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) @@ -118,6 +118,13 @@ steps: displayName: Run integration tests (Electron) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) +- script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \ + ./resources/server/test/test-web-integration.sh --browser webkit + displayName: Run integration tests (Browser) + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | set -e APP_ROOT=$(agent.builddirectory)/VSCode-darwin @@ -128,13 +135,6 @@ steps: displayName: Run remote integration tests (Electron) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \ - ./resources/server/test/test-web-integration.sh --browser webkit - displayName: Run integration tests (Browser) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - script: | set -e APP_ROOT=$(agent.builddirectory)/VSCode-darwin @@ -160,6 +160,13 @@ steps: continueOnError: true condition: failed() +- task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: '*-results.xml' + searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' + condition: succeededOrFailed() + - script: | set -e security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain diff --git a/build/azure-pipelines/linux/continuous-build-linux.yml b/build/azure-pipelines/linux/continuous-build-linux.yml index 0cffb4ba266..41225110f37 100644 --- a/build/azure-pipelines/linux/continuous-build-linux.yml +++ b/build/azure-pipelines/linux/continuous-build-linux.yml @@ -63,7 +63,7 @@ steps: displayName: Run Unit Tests (Electron) - script: | - DISPLAY=:10 yarn test-browser --browser chromium + DISPLAY=:10 yarn test-browser --browser chromium --tfs "Browser Unit Tests" displayName: Run Unit Tests (Browser) - script: | diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index dbd0621a273..21d963042c8 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -106,7 +106,7 @@ steps: - script: | set -e - DISPLAY=:10 yarn test-browser --build --browser chromium + DISPLAY=:10 yarn test-browser --build --browser chromium --tfs "Browser Unit Tests" displayName: Run unit tests (Browser) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) @@ -123,6 +123,13 @@ steps: displayName: Run integration tests (Electron) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) +- script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \ + DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium + displayName: Run integration tests (Browser) + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | set -e APP_ROOT=$(agent.builddirectory)/VSCode-linux-x64 @@ -133,13 +140,6 @@ steps: displayName: Run remote integration tests (Electron) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \ - DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium - displayName: Run integration tests (Browser) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - - task: PublishPipelineArtifact@0 inputs: artifactName: crash-dump-linux @@ -148,6 +148,13 @@ steps: continueOnError: true condition: failed() +- task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: '*-results.xml' + searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' + condition: succeededOrFailed() + - script: | set -e yarn gulp "vscode-linux-x64-build-deb" diff --git a/build/azure-pipelines/mixin.js b/build/azure-pipelines/mixin.js index 8d441e783a9..e133b2d2bb9 100644 --- a/build/azure-pipelines/mixin.js +++ b/build/azure-pipelines/mixin.js @@ -55,7 +55,7 @@ function main() { fancyLog(ansiColors.blue('[mixin]'), 'Inheriting OSS built-in extensions', builtInExtensions.map(e => e.name)); } - return { ...o, builtInExtensions }; + return { webBuiltInExtensions: ossProduct.webBuiltInExtensions, ...o, builtInExtensions }; })) .pipe(productJsonFilter.restore) .pipe(es.mapSync(function (f) { diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 7b6d2bcbbde..1f3a0805086 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -1,157 +1,3 @@ -resources: - containers: - - container: vscode-x64 - image: vscodehub.azurecr.io/vscode-linux-build-agent:x64 - endpoint: VSCodeHub - - container: snapcraft - image: snapcore/snapcraft:stable - -jobs: -- job: Compile - pool: - vmImage: 'Ubuntu-16.04' - container: vscode-x64 - steps: - - template: product-compile.yml - -- job: Windows - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32'], 'true')) - pool: - vmImage: VS2017-Win2016 - variables: - VSCODE_ARCH: x64 - dependsOn: - - Compile - steps: - - template: win32/product-build-win32.yml - -- job: Windows32 - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true')) - pool: - vmImage: VS2017-Win2016 - variables: - VSCODE_ARCH: ia32 - dependsOn: - - Compile - steps: - - template: win32/product-build-win32.yml - -- job: WindowsARM64 - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_ARM64'], 'true')) - pool: - vmImage: VS2017-Win2016 - variables: - VSCODE_ARCH: arm64 - dependsOn: - - Compile - steps: - - template: win32/product-build-win32-arm64.yml - -- job: Linux - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true')) - pool: - vmImage: 'Ubuntu-16.04' - container: vscode-x64 - dependsOn: - - Compile - steps: - - template: linux/product-build-linux.yml - -- job: LinuxSnap - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true')) - pool: - vmImage: 'Ubuntu-16.04' - container: snapcraft - dependsOn: Linux - steps: - - template: linux/snap-build-linux.yml - -- job: LinuxArmhf - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true')) - pool: - vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: armhf - dependsOn: - - Compile - steps: - - template: linux/product-build-linux-multiarch.yml - -- job: LinuxArm64 - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARM64'], 'true')) - pool: - vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: arm64 - dependsOn: - - Compile - steps: - - template: linux/product-build-linux-multiarch.yml - -- job: LinuxAlpine - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true')) - pool: - vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: alpine - dependsOn: - - Compile - steps: - - template: linux/product-build-linux-multiarch.yml - -- job: LinuxWeb - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WEB'], 'true')) - pool: - vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: x64 - dependsOn: - - Compile - steps: - - template: web/product-build-web.yml - -- job: macOS - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_MACOS'], 'true')) - pool: - vmImage: macOS-latest - dependsOn: - - Compile - steps: - - template: darwin/product-build-darwin.yml - -- job: Release - condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), or(eq(variables['VSCODE_RELEASE'], 'true'), and(or(eq(variables['VSCODE_QUALITY'], 'insider'), eq(variables['VSCODE_QUALITY'], 'exploration')), eq(variables['Build.Reason'], 'Schedule')))) - pool: - vmImage: 'Ubuntu-16.04' - dependsOn: - - Windows - - Windows32 - - Linux - - LinuxSnap - - LinuxArmhf - - LinuxArm64 - - LinuxAlpine - - macOS - steps: - - template: release.yml - -- job: Mooncake - pool: - vmImage: 'Ubuntu-16.04' - condition: and(succeededOrFailed(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) - dependsOn: - - Windows - - Windows32 - - Linux - - LinuxSnap - - LinuxArmhf - - LinuxArm64 - - LinuxAlpine - - LinuxWeb - - macOS - steps: - - template: sync-mooncake.yml - trigger: none pr: none @@ -161,3 +7,138 @@ schedules: branches: include: - master + +resources: + containers: + - container: vscode-x64 + image: vscodehub.azurecr.io/vscode-linux-build-agent:x64 + endpoint: VSCodeHub + - container: snapcraft + image: snapcore/snapcraft:stable + +stages: +- stage: Compile + jobs: + - job: Compile + pool: + vmImage: 'Ubuntu-16.04' + container: vscode-x64 + steps: + - template: product-compile.yml + +- stage: Windows + dependsOn: + - Compile + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) + pool: + vmImage: VS2017-Win2016 + jobs: + - job: Windows + condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32'], 'true')) + variables: + VSCODE_ARCH: x64 + steps: + - template: win32/product-build-win32.yml + + - job: Windows32 + condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true')) + variables: + VSCODE_ARCH: ia32 + steps: + - template: win32/product-build-win32.yml + + - job: WindowsARM64 + condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32_ARM64'], 'true')) + variables: + VSCODE_ARCH: arm64 + steps: + - template: win32/product-build-win32-arm64.yml + +- stage: Linux + dependsOn: + - Compile + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) + pool: + vmImage: 'Ubuntu-16.04' + jobs: + - job: Linux + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX'], 'true')) + container: vscode-x64 + steps: + - template: linux/product-build-linux.yml + + - job: LinuxSnap + dependsOn: + - Linux + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX'], 'true')) + container: snapcraft + steps: + - template: linux/snap-build-linux.yml + + - job: LinuxArmhf + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true')) + variables: + VSCODE_ARCH: armhf + steps: + - template: linux/product-build-linux-multiarch.yml + + - job: LinuxArm64 + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ARM64'], 'true')) + variables: + VSCODE_ARCH: arm64 + steps: + - template: linux/product-build-linux-multiarch.yml + + - job: LinuxAlpine + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true')) + variables: + VSCODE_ARCH: alpine + steps: + - template: linux/product-build-linux-multiarch.yml + + - job: LinuxWeb + condition: and(succeeded(), eq(variables['VSCODE_BUILD_WEB'], 'true')) + variables: + VSCODE_ARCH: x64 + steps: + - template: web/product-build-web.yml + +- stage: macOS + dependsOn: + - Compile + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) + pool: + vmImage: macOS-latest + jobs: + - job: macOS + condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS'], 'true')) + steps: + - template: darwin/product-build-darwin.yml + +- stage: Mooncake + dependsOn: + - Windows + - Linux + - macOS + condition: and(succeededOrFailed(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) + pool: + vmImage: 'Ubuntu-16.04' + jobs: + - job: SyncMooncake + displayName: Sync Mooncake + steps: + - template: sync-mooncake.yml + +- stage: Publish + dependsOn: + - Windows + - Linux + - macOS + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), or(eq(variables['VSCODE_RELEASE'], 'true'), and(or(eq(variables['VSCODE_QUALITY'], 'insider'), eq(variables['VSCODE_QUALITY'], 'exploration')), eq(variables['Build.Reason'], 'Schedule')))) + pool: + vmImage: 'Ubuntu-16.04' + jobs: + - job: BuildService + displayName: Build Service + steps: + - template: release.yml diff --git a/build/azure-pipelines/publish-types/update-types.ts b/build/azure-pipelines/publish-types/update-types.ts index a5ef449b77b..9603726bebf 100644 --- a/build/azure-pipelines/publish-types/update-types.ts +++ b/build/azure-pipelines/publish-types/update-types.ts @@ -36,6 +36,18 @@ function updateDTSFile(outPath: string, tag: string) { fs.writeFileSync(outPath, newContent); } +function repeat(str: string, times: number): string { + const result = new Array(times); + for (let i = 0; i < times; i++) { + result[i] = str; + } + return result.join(''); +} + +function convertTabsToSpaces(str: string): string { + return str.replace(/\t/gm, value => repeat(' ', value.length)); +} + function getNewFileContent(content: string, tag: string) { const oldheader = [ `/*---------------------------------------------------------------------------------------------`, @@ -44,7 +56,7 @@ function getNewFileContent(content: string, tag: string) { ` *--------------------------------------------------------------------------------------------*/` ].join('\n'); - return getNewFileHeader(tag) + content.slice(oldheader.length); + return convertTabsToSpaces(getNewFileHeader(tag) + content.slice(oldheader.length)); } function getNewFileHeader(tag: string) { diff --git a/build/azure-pipelines/win32/continuous-build-win32.yml b/build/azure-pipelines/win32/continuous-build-win32.yml index cbe4a8ac85f..8600377139c 100644 --- a/build/azure-pipelines/win32/continuous-build-win32.yml +++ b/build/azure-pipelines/win32/continuous-build-win32.yml @@ -57,7 +57,7 @@ steps: displayName: Run Unit Tests (Electron) - powershell: | - yarn test-browser --browser chromium --browser firefox + yarn test-browser --browser chromium --browser firefox --tfs "Browser Unit Tests" displayName: Run Unit Tests (Browser) - powershell: | diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index c233d5c6d29..be80731a7ab 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -115,7 +115,7 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { yarn test-browser --build --browser chromium --browser firefox } + exec { yarn test-browser --build --browser chromium --browser firefox --tfs "Browser Unit Tests" } displayName: Run unit tests (Browser) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) @@ -135,18 +135,18 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json - $AppNameShort = $AppProductJson.nameShort - exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-remote-integration.bat } - displayName: Run remote integration tests (Electron) + exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-web-integration.bat --browser firefox } + displayName: Run integration tests (Browser) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-web-integration.bat --browser firefox } - displayName: Run integration tests (Browser) + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json + $AppNameShort = $AppProductJson.nameShort + exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-remote-integration.bat } + displayName: Run remote integration tests (Electron) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - task: PublishPipelineArtifact@0 @@ -157,6 +157,13 @@ steps: continueOnError: true condition: failed() +- task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: '*-results.xml' + searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' + condition: succeededOrFailed() + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 inputs: ConnectedServiceName: 'ESRP CodeSign' diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 6f7a9e678b4..6ae72e4cf06 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -165,8 +165,8 @@ gulp.task(compileExtensionsBuildLegacyTask); const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions')); const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series( cleanExtensionsBuildTask, - task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream().pipe(gulp.dest('.build'))), - task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream().pipe(gulp.dest('.build'))), + task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream(false).pipe(gulp.dest('.build'))), + task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false).pipe(gulp.dest('.build'))), )); gulp.task(compileExtensionsBuildTask); diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 2fbd50c18aa..4952ee1c26d 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -41,8 +41,8 @@ const indentationFilter = [ '**', // except specific files - '!ThirdPartyNotices.txt', - '!LICENSE.{txt,rtf}', + '!**/ThirdPartyNotices.txt', + '!**/LICENSE.{txt,rtf}', '!LICENSES.chromium.html', '!**/LICENSE', '!src/vs/nls.js', @@ -119,12 +119,12 @@ const copyrightFilter = [ '!resources/linux/snap/snapcraft.yaml', '!resources/linux/snap/electron-launch', '!resources/win32/bin/code.js', + '!resources/web/code-web.js', '!resources/completions/**', '!extensions/markdown-language-features/media/highlight.css', '!extensions/html-language-features/server/src/modes/typescript/*', '!extensions/*/server/bin/*', - '!src/vs/editor/test/node/classification/typescript-test.ts', - '!resources/serverless/code-web.js' + '!src/vs/editor/test/node/classification/typescript-test.ts' ]; const jsHygieneFilter = [ diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 60777cb42cc..3eb2cfdc4fe 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -77,9 +77,9 @@ const vscodeResources = [ 'out-build/vs/platform/files/**/*.md', 'out-build/vs/code/electron-browser/workbench/**', 'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js', - 'out-build/vs/code/electron-browser/issue/issueReporter.js', + 'out-build/vs/code/electron-sandbox/issue/issueReporter.js', 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.js', - 'out-build/vs/platform/auth/common/auth.css', + 'out-build/vs/code/electron-sandbox/proxy/auth.js', '!**/test/**' ]; diff --git a/build/lib/builtInExtensions.js b/build/lib/builtInExtensions.js index ebcf8bc8ddb..f86414211ec 100644 --- a/build/lib/builtInExtensions.js +++ b/build/lib/builtInExtensions.js @@ -18,7 +18,9 @@ const fancyLog = require('fancy-log'); const ansiColors = require('ansi-colors'); const root = path.dirname(path.dirname(__dirname)); -const builtInExtensions = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')).builtInExtensions; +const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); +const builtInExtensions = productjson.builtInExtensions; +const webBuiltInExtensions = productjson.webBuiltInExtensions; const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json'); const ENABLE_LOGGING = !process.env['VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE']; @@ -100,14 +102,14 @@ function writeControlFile(control) { fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2)); } -function main() { +exports.getBuiltInExtensions = function getBuiltInExtensions() { log('Syncronizing built-in extensions...'); log(`You can manage built-in extensions with the ${ansiColors.cyan('--builtin')} flag`); const control = readControlFile(); const streams = []; - for (const extension of builtInExtensions) { + for (const extension of [...builtInExtensions, ...webBuiltInExtensions]) { let controlState = control[extension.name] || 'marketplace'; control[extension.name] = controlState; @@ -116,14 +118,16 @@ function main() { writeControlFile(control); - es.merge(streams) - .on('error', err => { - console.error(err); - process.exit(1); - }) - .on('end', () => { - process.exit(0); - }); -} + return new Promise((resolve, reject) => { + es.merge(streams) + .on('error', reject) + .on('end', resolve); + }); +}; -main(); +if (require.main === module) { + exports.getBuiltInExtensions().then(() => process.exit(0)).catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/lib/extensions.js b/build/lib/extensions.js index d289ccf9107..fe0deffc6d0 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.translatePackageJSON = exports.scanBuiltinExtensions = exports.packageMarketplaceWebExtensionsStream = exports.packageMarketplaceExtensionsStream = exports.packageLocalWebExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0; +exports.translatePackageJSON = exports.scanBuiltinExtensions = exports.packageMarketplaceExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0; const es = require("event-stream"); const fs = require("fs"); const glob = require("glob"); @@ -22,22 +22,28 @@ const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); const buffer = require('gulp-buffer'); const json = require("gulp-json-editor"); +const jsoncParser = require("jsonc-parser"); const webpack = require('webpack'); const webpackGulp = require('webpack-stream'); const util = require('./util'); const root = path.dirname(path.dirname(__dirname)); const commit = util.getVersion(root); const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; -function minimizeLanguageJSON(input) { - const tmLanguageJsonFilter = filter('**/*.tmLanguage.json', { restore: true }); +function minifyExtensionResources(input) { + const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true }); return input - .pipe(tmLanguageJsonFilter) + .pipe(jsonFilter) .pipe(buffer()) .pipe(es.mapSync((f) => { - f.contents = Buffer.from(JSON.stringify(JSON.parse(f.contents.toString('utf8')))); + const errors = []; + const value = jsoncParser.parse(f.contents.toString('utf8'), errors); + if (errors.length === 0) { + // file parsed OK => just stringify to drop whitespace and comments + f.contents = Buffer.from(JSON.stringify(value)); + } return f; })) - .pipe(tmLanguageJsonFilter.restore); + .pipe(jsonFilter.restore); } function updateExtensionPackageJSON(input, update) { const packageJsonFilter = filter('extensions/*/package.json', { restore: true }); @@ -57,24 +63,18 @@ function fromLocal(extensionPath, forWeb) { let input = isWebPacked ? fromLocalWebpack(extensionPath, webpackConfigFileName) : fromLocalNormal(extensionPath); - if (forWeb) { - input = updateExtensionPackageJSON(input, (data) => { - if (data.browser) { - data.main = data.browser; - } - data.extensionKind = ['web']; - return data; - }); - } - else if (isWebPacked) { + if (isWebPacked) { input = updateExtensionPackageJSON(input, (data) => { + delete data.scripts; + delete data.dependencies; + delete data.devDependencies; if (data.main) { data.main = data.main.replace('/out/', /dist/); } return data; }); } - return minimizeLanguageJSON(input); + return input; } function fromLocalWebpack(extensionPath, webpackConfigFileName) { const result = es.through(); @@ -193,104 +193,110 @@ function fromMarketplace(extensionName, version, metadata) { exports.fromMarketplace = fromMarketplace; const excludedExtensions = [ 'vscode-api-tests', - 'vscode-web-playground', 'vscode-colorize-tests', 'vscode-test-resolver', 'ms-vscode.node-debug', 'ms-vscode.node-debug2', - 'vscode-notebook-tests' + 'vscode-notebook-tests', + 'vscode-custom-editor-tests', ]; -const builtInExtensions = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')).builtInExtensions; -function packageLocalExtensionsStream() { - const localExtensionDescriptions = glob.sync('extensions/*/package.json') +const marketplaceWebExtensions = [ + 'ms-vscode.references-view' +]; +const productJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); +const builtInExtensions = productJson.builtInExtensions || []; +const webBuiltInExtensions = productJson.webBuiltInExtensions || []; +/** + * Loosely based on `getExtensionKind` from `src/vs/workbench/services/extensions/common/extensionsUtil.ts` + */ +function isWebExtension(manifest) { + if (typeof manifest.extensionKind !== 'undefined') { + const extensionKind = Array.isArray(manifest.extensionKind) ? manifest.extensionKind : [manifest.extensionKind]; + return (extensionKind.indexOf('web') >= 0); + } + return (!Boolean(manifest.main) || Boolean(manifest.browser)); +} +function packageLocalExtensionsStream(forWeb) { + const localExtensionsDescriptions = (glob.sync('extensions/*/package.json') .map(manifestPath => { + const absoluteManifestPath = path.join(root, manifestPath); const extensionPath = path.dirname(path.join(root, manifestPath)); const extensionName = path.basename(extensionPath); - return { name: extensionName, path: extensionPath }; + return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath }; }) .filter(({ name }) => excludedExtensions.indexOf(name) === -1) - .filter(({ name }) => builtInExtensions.every(b => b.name !== name)); - const localExtensions = localExtensionDescriptions.map(extension => { - return fromLocal(extension.path, false) + .filter(({ name }) => builtInExtensions.every(b => b.name !== name)) + .filter(({ manifestPath }) => (forWeb ? isWebExtension(require(manifestPath)) : true))); + const localExtensionsStream = minifyExtensionResources(es.merge(...localExtensionsDescriptions.map(extension => { + return fromLocal(extension.path, forWeb) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }); - const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); - return es.merge(nodeModules, ...localExtensions) - .pipe(util2.setExecutableBit(['**/*.sh'])); + }))); + let result; + if (forWeb) { + result = localExtensionsStream; + } + else { + // also include shared node modules + result = es.merge(localExtensionsStream, gulp.src('extensions/node_modules/**', { base: '.' })); + } + return (result + .pipe(util2.setExecutableBit(['**/*.sh']))); } exports.packageLocalExtensionsStream = packageLocalExtensionsStream; -function packageLocalWebExtensionsStream() { - const localExtensionDescriptions = glob.sync('extensions/*/package.json') - .filter(manifestPath => { - const packageJsonConfig = require(path.join(root, manifestPath)); - return !packageJsonConfig.main || packageJsonConfig.browser; - }) - .map(manifestPath => { - const extensionPath = path.dirname(path.join(root, manifestPath)); - const extensionName = path.basename(extensionPath); - return { name: extensionName, path: extensionPath }; - }); - return es.merge(...localExtensionDescriptions.map(extension => { - return fromLocal(extension.path, true) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })); -} -exports.packageLocalWebExtensionsStream = packageLocalWebExtensionsStream; -function packageMarketplaceExtensionsStream() { - const extensions = builtInExtensions.map(extension => { - return fromMarketplace(extension.name, extension.version, extension.metadata) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }); - return es.merge(extensions) - .pipe(util2.setExecutableBit(['**/*.sh'])); -} -exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream; -function packageMarketplaceWebExtensionsStream(builtInExtensions) { - const extensions = builtInExtensions +function packageMarketplaceExtensionsStream(forWeb) { + const marketplaceExtensionsDescriptions = [ + ...builtInExtensions.filter(({ name }) => (forWeb ? marketplaceWebExtensions.indexOf(name) >= 0 : true)), + ...(forWeb ? webBuiltInExtensions : []) + ]; + const marketplaceExtensionsStream = minifyExtensionResources(es.merge(...marketplaceExtensionsDescriptions .map(extension => { const input = fromMarketplace(extension.name, extension.version, extension.metadata) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); return updateExtensionPackageJSON(input, (data) => { - if (data.main) { - data.browser = data.main; - } - data.extensionKind = ['web']; + delete data.scripts; + delete data.dependencies; + delete data.devDependencies; return data; }); - }); - return es.merge(extensions); + }))); + return (marketplaceExtensionsStream + .pipe(util2.setExecutableBit(['**/*.sh']))); } -exports.packageMarketplaceWebExtensionsStream = packageMarketplaceWebExtensionsStream; -function scanBuiltinExtensions(extensionsRoot, forWeb) { +exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream; +function scanBuiltinExtensions(extensionsRoot, exclude = []) { const scannedExtensions = []; - const extensionsFolders = fs.readdirSync(extensionsRoot); - for (const extensionFolder of extensionsFolders) { - const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); - if (!fs.existsSync(packageJSONPath)) { - continue; + try { + const extensionsFolders = fs.readdirSync(extensionsRoot); + for (const extensionFolder of extensionsFolders) { + if (exclude.indexOf(extensionFolder) >= 0) { + continue; + } + const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); + if (!fs.existsSync(packageJSONPath)) { + continue; + } + let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); + if (!isWebExtension(packageJSON)) { + continue; + } + const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); + const packageNLSPath = children.filter(child => child === 'package.nls.json')[0]; + const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined; + const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; + const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; + scannedExtensions.push({ + extensionPath: extensionFolder, + packageJSON, + packageNLS, + readmePath: readme ? path.join(extensionFolder, readme) : undefined, + changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, + }); } - let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); - const extensionKind = packageJSON['extensionKind'] || []; - if (forWeb && extensionKind.indexOf('web') === -1) { - continue; - } - const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); - const packageNLS = children.filter(child => child === 'package.nls.json')[0]; - const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; - const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; - if (packageNLS) { - // temporary - packageJSON = translatePackageJSON(packageJSON, path.join(extensionsRoot, extensionFolder, packageNLS)); - } - scannedExtensions.push({ - extensionPath: extensionFolder, - packageJSON, - packageNLSPath: packageNLS ? path.join(extensionFolder, packageNLS) : undefined, - readmePath: readme ? path.join(extensionFolder, readme) : undefined, - changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, - }); + return scannedExtensions; + } + catch (ex) { + return scannedExtensions; } - return scannedExtensions; } exports.scanBuiltinExtensions = scanBuiltinExtensions; function translatePackageJSON(packageJSON, packageNLSPath) { diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 3810723d7d4..dac71c81479 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -21,6 +21,7 @@ import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; const buffer = require('gulp-buffer'); import json = require('gulp-json-editor'); +import * as jsoncParser from 'jsonc-parser'; const webpack = require('webpack'); const webpackGulp = require('webpack-stream'); const util = require('./util'); @@ -28,16 +29,21 @@ const root = path.dirname(path.dirname(__dirname)); const commit = util.getVersion(root); const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; -function minimizeLanguageJSON(input: Stream): Stream { - const tmLanguageJsonFilter = filter('**/*.tmLanguage.json', { restore: true }); +function minifyExtensionResources(input: Stream): Stream { + const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true }); return input - .pipe(tmLanguageJsonFilter) + .pipe(jsonFilter) .pipe(buffer()) .pipe(es.mapSync((f: File) => { - f.contents = Buffer.from(JSON.stringify(JSON.parse(f.contents.toString('utf8')))); + const errors: jsoncParser.ParseError[] = []; + const value = jsoncParser.parse(f.contents.toString('utf8'), errors); + if (errors.length === 0) { + // file parsed OK => just stringify to drop whitespace and comments + f.contents = Buffer.from(JSON.stringify(value)); + } return f; })) - .pipe(tmLanguageJsonFilter.restore); + .pipe(jsonFilter.restore); } function updateExtensionPackageJSON(input: Stream, update: (data: any) => any): Stream { @@ -61,16 +67,11 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream { ? fromLocalWebpack(extensionPath, webpackConfigFileName) : fromLocalNormal(extensionPath); - if (forWeb) { - input = updateExtensionPackageJSON(input, (data: any) => { - if (data.browser) { - data.main = data.browser; - } - data.extensionKind = ['web']; - return data; - }); - } else if (isWebPacked) { + if (isWebPacked) { input = updateExtensionPackageJSON(input, (data: any) => { + delete data.scripts; + delete data.dependencies; + delete data.devDependencies; if (data.main) { data.main = data.main.replace('/out/', /dist/); } @@ -78,7 +79,7 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream { }); } - return minimizeLanguageJSON(input); + return input; } @@ -223,15 +224,18 @@ export function fromMarketplace(extensionName: string, version: string, metadata .pipe(json({ __metadata: metadata })) .pipe(packageJsonFilter.restore); } - const excludedExtensions = [ 'vscode-api-tests', - 'vscode-web-playground', 'vscode-colorize-tests', 'vscode-test-resolver', 'ms-vscode.node-debug', 'ms-vscode.node-debug2', - 'vscode-notebook-tests' + 'vscode-notebook-tests', + 'vscode-custom-editor-tests', +]; + +const marketplaceWebExtensions = [ + 'ms-vscode.references-view' ]; interface IBuiltInExtension { @@ -241,112 +245,133 @@ interface IBuiltInExtension { metadata: any; } -const builtInExtensions: IBuiltInExtension[] = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')).builtInExtensions; +const productJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); +const builtInExtensions: IBuiltInExtension[] = productJson.builtInExtensions || []; +const webBuiltInExtensions: IBuiltInExtension[] = productJson.webBuiltInExtensions || []; -export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream { - const localExtensionDescriptions = (glob.sync('extensions/*/package.json')) - .map(manifestPath => { - const extensionPath = path.dirname(path.join(root, manifestPath)); - const extensionName = path.basename(extensionPath); - return { name: extensionName, path: extensionPath }; - }) - .filter(({ name }) => excludedExtensions.indexOf(name) === -1) - .filter(({ name }) => builtInExtensions.every(b => b.name !== name)); - - - const localExtensions = localExtensionDescriptions.map(extension => { - return fromLocal(extension.path, false) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }); - - const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); - return es.merge(nodeModules, ...localExtensions) - .pipe(util2.setExecutableBit(['**/*.sh'])); +type ExtensionKind = 'ui' | 'workspace' | 'web'; +interface IExtensionManifest { + main: string; + browser: string; + extensionKind?: ExtensionKind | ExtensionKind[]; +} +/** + * Loosely based on `getExtensionKind` from `src/vs/workbench/services/extensions/common/extensionsUtil.ts` + */ +function isWebExtension(manifest: IExtensionManifest): boolean { + if (typeof manifest.extensionKind !== 'undefined') { + const extensionKind = Array.isArray(manifest.extensionKind) ? manifest.extensionKind : [manifest.extensionKind]; + return (extensionKind.indexOf('web') >= 0); + } + return (!Boolean(manifest.main) || Boolean(manifest.browser)); } -export function packageLocalWebExtensionsStream(): NodeJS.ReadWriteStream { - const localExtensionDescriptions = (glob.sync('extensions/*/package.json')) - .filter(manifestPath => { - const packageJsonConfig = require(path.join(root, manifestPath)); - return !packageJsonConfig.main || packageJsonConfig.browser; - }) - .map(manifestPath => { - const extensionPath = path.dirname(path.join(root, manifestPath)); - const extensionName = path.basename(extensionPath); - return { name: extensionName, path: extensionPath }; - }); +export function packageLocalExtensionsStream(forWeb: boolean): Stream { + const localExtensionsDescriptions = ( + (glob.sync('extensions/*/package.json')) + .map(manifestPath => { + const absoluteManifestPath = path.join(root, manifestPath); + const extensionPath = path.dirname(path.join(root, manifestPath)); + const extensionName = path.basename(extensionPath); + return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath }; + }) + .filter(({ name }) => excludedExtensions.indexOf(name) === -1) + .filter(({ name }) => builtInExtensions.every(b => b.name !== name)) + .filter(({ manifestPath }) => (forWeb ? isWebExtension(require(manifestPath)) : true)) + ); + const localExtensionsStream = minifyExtensionResources( + es.merge( + ...localExtensionsDescriptions.map(extension => { + return fromLocal(extension.path, forWeb) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); + }) + ) + ); - return es.merge(...localExtensionDescriptions.map(extension => { - return fromLocal(extension.path, true) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })); + let result: Stream; + if (forWeb) { + result = localExtensionsStream; + } else { + // also include shared node modules + result = es.merge(localExtensionsStream, gulp.src('extensions/node_modules/**', { base: '.' })); + } + + return ( + result + .pipe(util2.setExecutableBit(['**/*.sh'])) + ); } -export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream { - const extensions = builtInExtensions.map(extension => { - return fromMarketplace(extension.name, extension.version, extension.metadata) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }); +export function packageMarketplaceExtensionsStream(forWeb: boolean): Stream { + const marketplaceExtensionsDescriptions = [ + ...builtInExtensions.filter(({ name }) => (forWeb ? marketplaceWebExtensions.indexOf(name) >= 0 : true)), + ...(forWeb ? webBuiltInExtensions : []) + ]; + const marketplaceExtensionsStream = minifyExtensionResources( + es.merge( + ...marketplaceExtensionsDescriptions + .map(extension => { + const input = fromMarketplace(extension.name, extension.version, extension.metadata) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); + return updateExtensionPackageJSON(input, (data: any) => { + delete data.scripts; + delete data.dependencies; + delete data.devDependencies; + return data; + }); + }) + ) + ); - return es.merge(extensions) - .pipe(util2.setExecutableBit(['**/*.sh'])); -} - -export function packageMarketplaceWebExtensionsStream(builtInExtensions: IBuiltInExtension[]): NodeJS.ReadWriteStream { - const extensions = builtInExtensions - .map(extension => { - const input = fromMarketplace(extension.name, extension.version, extension.metadata) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - return updateExtensionPackageJSON(input, (data: any) => { - if (data.main) { - data.browser = data.main; - } - data.extensionKind = ['web']; - return data; - }); - }); - return es.merge(extensions); + return ( + marketplaceExtensionsStream + .pipe(util2.setExecutableBit(['**/*.sh'])) + ); } export interface IScannedBuiltinExtension { - extensionPath: string, - packageJSON: any, - packageNLSPath?: string, - readmePath?: string, - changelogPath?: string, + extensionPath: string; + packageJSON: any; + packageNLS?: any; + readmePath?: string; + changelogPath?: string; } -export function scanBuiltinExtensions(extensionsRoot: string, forWeb: boolean): IScannedBuiltinExtension[] { +export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] = []): IScannedBuiltinExtension[] { const scannedExtensions: IScannedBuiltinExtension[] = []; - const extensionsFolders = fs.readdirSync(extensionsRoot); - for (const extensionFolder of extensionsFolders) { - const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); - if (!fs.existsSync(packageJSONPath)) { - continue; - } - let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); - const extensionKind: string[] = packageJSON['extensionKind'] || []; - if (forWeb && extensionKind.indexOf('web') === -1) { - continue; - } - const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); - const packageNLS = children.filter(child => child === 'package.nls.json')[0]; - const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; - const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; - if (packageNLS) { - // temporary - packageJSON = translatePackageJSON(packageJSON, path.join(extensionsRoot, extensionFolder, packageNLS)) + try { + const extensionsFolders = fs.readdirSync(extensionsRoot); + for (const extensionFolder of extensionsFolders) { + if (exclude.indexOf(extensionFolder) >= 0) { + continue; + } + const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); + if (!fs.existsSync(packageJSONPath)) { + continue; + } + let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); + if (!isWebExtension(packageJSON)) { + continue; + } + const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); + const packageNLSPath = children.filter(child => child === 'package.nls.json')[0]; + const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined; + const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; + const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; + + scannedExtensions.push({ + extensionPath: extensionFolder, + packageJSON, + packageNLS, + readmePath: readme ? path.join(extensionFolder, readme) : undefined, + changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, + }); } - scannedExtensions.push({ - extensionPath: extensionFolder, - packageJSON, - packageNLSPath: packageNLS ? path.join(extensionFolder, packageNLS) : undefined, - readmePath: readme ? path.join(extensionFolder, readme) : undefined, - changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, - }); + return scannedExtensions; + } catch (ex) { + return scannedExtensions; } - return scannedExtensions; } export function translatePackageJSON(packageJSON: string, packageNLSPath: string) { diff --git a/build/lib/optimize.js b/build/lib/optimize.js index 5015f76649b..5403c105620 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -70,7 +70,7 @@ function loader(src, bundledFileHeader, bundleLoader) { })) .pipe(concat('vs/loader.js'))); } -function toConcatStream(src, bundledFileHeader, sources, dest) { +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 @@ -91,10 +91,12 @@ function toConcatStream(src, bundledFileHeader, sources, dest) { 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: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake', + path: path, base: base, - contents: Buffer.from(source.contents) + contents: Buffer.from(contents) }); }); return es.readArray(treatedSources) @@ -102,9 +104,9 @@ function toConcatStream(src, bundledFileHeader, sources, dest) { .pipe(concat(dest)) .pipe(stats_1.createStatsStream(dest)); } -function toBundleStream(src, bundledFileHeader, bundles) { +function toBundleStream(src, bundledFileHeader, bundles, fileContentMapper) { return es.merge(bundles.map(function (bundle) { - return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest); + return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper); })); } const DEFAULT_FILE_HEADER = [ @@ -120,6 +122,7 @@ function optimizeTask(opts) { const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const out = opts.out; + const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents); return function () { const bundlesStream = es.through(); // this stream will contain the bundled files const resourcesStream = es.through(); // this stream will contain the resources @@ -128,7 +131,7 @@ function optimizeTask(opts) { if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } - toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream); + toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream); // Remove css inlined resources const filteredResources = resources.slice(); result.cssInlinedResources.forEach(function (resource) { diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index 1fd00c15cb9..2822803f9f7 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -18,7 +18,6 @@ import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; import * as path from 'path'; import * as pump from 'pump'; -import * as sm from 'source-map'; import * as terser from 'terser'; import * as VinylFile from 'vinyl'; import * as bundle from './bundle'; @@ -48,10 +47,6 @@ export function loaderConfig() { const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i; -declare class FileSourceMap extends VinylFile { - public sourceMap: sm.RawSourceMap; -} - function loader(src: string, bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWriteStream { let sources = [ `${src}/vs/loader.js` @@ -84,7 +79,7 @@ function loader(src: string, bundledFileHeader: string, bundleLoader: boolean): ); } -function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.IFile[], dest: string): NodeJS.ReadWriteStream { +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 @@ -108,11 +103,13 @@ function toConcatStream(src: string, bundledFileHeader: string, sources: bundle. 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: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake', + path: path, base: base, - contents: Buffer.from(source.contents) + contents: Buffer.from(contents) }); }); @@ -122,9 +119,9 @@ function toConcatStream(src: string, bundledFileHeader: string, sources: bundle. .pipe(createStatsStream(dest)); } -function toBundleStream(src: string, bundledFileHeader: string, bundles: bundle.IConcatFile[]): NodeJS.ReadWriteStream { +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); + return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper); })); } @@ -162,6 +159,12 @@ export interface IOptimizeTaskOpts { * (out folder name) */ languages?: Language[]; + /** + * File contents interceptor + * @param contents The contens of the file + * @param path The absolute file path, always using `/`, even on Windows + */ + fileContentMapper?: (contents: string, path: string) => string; } const DEFAULT_FILE_HEADER = [ @@ -178,6 +181,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const out = opts.out; + const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents); return function () { const bundlesStream = es.through(); // this stream will contain the bundled files @@ -187,7 +191,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr bundle.bundle(entryPoints, loaderConfig, function (err, result) { if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } - toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream); + toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream); // Remove css inlined resources const filteredResources = resources.slice(); diff --git a/build/lib/preLaunch.js b/build/lib/preLaunch.js new file mode 100644 index 00000000000..1aecbe19048 --- /dev/null +++ b/build/lib/preLaunch.js @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; +Object.defineProperty(exports, "__esModule", { value: true }); +// @ts-check +const path = require("path"); +const child_process_1 = require("child_process"); +const fs_1 = require("fs"); +const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn'; +const rootDir = path.resolve(__dirname, '..', '..'); +function runProcess(command, args = []) { + return new Promise((resolve, reject) => { + const child = child_process_1.spawn(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env }); + child.on('exit', err => !err ? resolve() : process.exit(err !== null && err !== void 0 ? err : 1)); + child.on('error', reject); + }); +} +async function exists(subdir) { + try { + await fs_1.promises.stat(path.join(rootDir, subdir)); + return true; + } + catch (_a) { + return false; + } +} +async function ensureNodeModules() { + if (!(await exists('node_modules'))) { + await runProcess(yarn); + } +} +async function getElectron() { + await runProcess(yarn, ['electron']); +} +async function ensureCompiled() { + if (!(await exists('out'))) { + await runProcess(yarn, ['compile']); + } +} +async function main() { + await ensureNodeModules(); + await getElectron(); + await ensureCompiled(); + // Can't require this until after dependencies are installed + const { getBuiltInExtensions } = require('./builtInExtensions'); + await getBuiltInExtensions(); +} +if (require.main === module) { + main().catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/lib/preLaunch.ts b/build/lib/preLaunch.ts new file mode 100644 index 00000000000..bd084f5fec5 --- /dev/null +++ b/build/lib/preLaunch.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +// @ts-check + +import * as path from 'path'; +import { spawn } from 'child_process'; +import { promises as fs } from 'fs'; + +const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn'; +const rootDir = path.resolve(__dirname, '..', '..'); + +function runProcess(command: string, args: ReadonlyArray = []) { + return new Promise((resolve, reject) => { + const child = spawn(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env }); + child.on('exit', err => !err ? resolve() : process.exit(err ?? 1)); + child.on('error', reject); + }); +} + +async function exists(subdir: string) { + try { + await fs.stat(path.join(rootDir, subdir)); + return true; + } catch { + return false; + } +} + +async function ensureNodeModules() { + if (!(await exists('node_modules'))) { + await runProcess(yarn); + } +} + +async function getElectron() { + await runProcess(yarn, ['electron']); +} + +async function ensureCompiled() { + if (!(await exists('out'))) { + await runProcess(yarn, ['compile']); + } +} + +async function main() { + await ensureNodeModules(); + await getElectron(); + await ensureCompiled(); + + // Can't require this until after dependencies are installed + const { getBuiltInExtensions } = require('./builtInExtensions'); + await getBuiltInExtensions(); +} + +if (require.main === module) { + main().catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/package.json b/build/package.json index 22206229ffb..7392e4b602c 100644 --- a/build/package.json +++ b/build/package.json @@ -39,12 +39,13 @@ "gulp-sourcemaps": "^1.11.0", "gulp-uglify": "^3.0.0", "iconv-lite-umd": "0.6.8", + "jsonc-parser": "^2.3.0", "mime": "^1.3.4", "minimatch": "3.0.4", "minimist": "^1.2.3", "request": "^2.85.0", "terser": "4.3.8", - "typescript": "^4.0.0-dev.20200722", + "typescript": "^4.0.1-rc", "vsce": "1.48.0", "vscode-telemetry-extractor": "^1.6.0", "xml2js": "^0.4.17" diff --git a/build/tsconfig.json b/build/tsconfig.json index df15ccdd1be..f075fe3d4f5 100644 --- a/build/tsconfig.json +++ b/build/tsconfig.json @@ -14,7 +14,8 @@ "checkJs": true, "strict": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "newLine": "lf" }, "include": [ "**/*.ts" diff --git a/build/yarn.lock b/build/yarn.lock index 79909133c5b..d610f9cefa7 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -1600,6 +1600,11 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +jsonc-parser@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.0.tgz#7c7fc988ee1486d35734faaaa866fadb00fa91ee" + integrity sha512-b0EBt8SWFNnixVdvoR2ZtEGa9ZqLhbJnOjezn+WP+8kspFm+PFYDN8Z4Bc7pRlDjvuVcADSUkroIuTWWn/YiIA== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -2530,10 +2535,10 @@ typescript@^3.0.1: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== -typescript@^4.0.0-dev.20200722: - version "4.0.0-dev.20200722" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200722.tgz#b59dd5a3cd84a98d5aae0e4f3a3c58f0c81a3b9b" - integrity sha512-MmJ1YyPNK3JYeKLiTg5sQXdeZaMgt99Fg4BMRZhJmhoq1/x2V1cpXMYvE1rtIYl9K7NvmTDdU3WDW7ZOD6ybaw== +typescript@^4.0.1-rc: + version "4.0.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.1-rc.tgz#8adc78223eae56fe71d906a5fa90c3543b07a677" + integrity sha512-TCkspT3dSKOykbzS3/WSK7pqU2h1d/lEO6i45Afm5Y3XNAEAo8YXTG3kHOQk/wFq/5uPyO1+X8rb/Q+g7UsxJw== typical@^4.0.0: version "4.0.0" diff --git a/cglicenses.json b/cglicenses.json index f2d5a39a2b1..0da22bd9f57 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -330,5 +330,34 @@ "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", "SOFTWARE." ] + }, + { + // Reason: The license at https://github.com/colorjs/color-name/blob/master/LICENSE + // cannot be found by the OSS tool automatically. + "name": "color-name", + "fullLicenseText": [ + "The MIT License (MIT)", + "Copyright (c) 2015 Dmitry Ivanov", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] + }, + { + // Reason: The license cannot be found by the tool due to access controls on the repository + "name": "tas-client", + "fullLicenseText": [ + "MIT License", + "Copyright (c) 2020 - present Microsoft Corporation", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] } ] diff --git a/cgmanifest.json b/cgmanifest.json index 29afebf6b08..576724e75af 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "a822d2639a9c9c2c670e91d73f78e921865ce38e" + "commitHash": "0c2cb59b6283fe8d6bb4b14f8a832e2166aeaa0c" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "9.1.0" + "version": "9.2.0" }, { "component": { diff --git a/extensions/configuration-editing/schemas/attachContainer.schema.json b/extensions/configuration-editing/schemas/attachContainer.schema.json index da06cb1c9ff..fc53bb896f1 100644 --- a/extensions/configuration-editing/schemas/attachContainer.schema.json +++ b/extensions/configuration-editing/schemas/attachContainer.schema.json @@ -46,6 +46,15 @@ "errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'." } }, + "userEnvProbe": { + "type": "string", + "enum": [ + "none", + "loginInteractiveShell", + "interactiveShell" + ], + "description": "User environment probe to run. The default is none." + }, "postAttachCommand": { "type": [ "string", diff --git a/extensions/configuration-editing/schemas/devContainer.schema.json b/extensions/configuration-editing/schemas/devContainer.schema.json index 596672dede5..999a50e7788 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.json @@ -92,6 +92,15 @@ "type": "integer", "description": "The port VS Code can use to connect to its backend." }, + "userEnvProbe": { + "type": "string", + "enum": [ + "none", + "loginInteractiveShell", + "interactiveShell" + ], + "description": "User environment probe to run. The default is none." + }, "codespaces": { "type": "object", "description": "Codespaces-specific configuration." diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index 4a7f80c2a2a..5e466c2eb6f 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -42,11 +42,11 @@ export class SettingsDocument { }); } - // sync.ignoredExtensions - if (location.path[0] === 'sync.ignoredExtensions') { + // settingsSync.ignoredExtensions + if (location.path[0] === 'settingsSync.ignoredExtensions') { let ignoredExtensions = []; try { - ignoredExtensions = parse(this.document.getText())['sync.ignoredExtensions']; + ignoredExtensions = parse(this.document.getText())['settingsSync.ignoredExtensions']; } catch (e) {/* ignore error */ } return provideInstalledExtensionProposals(ignoredExtensions, range, true); } @@ -223,7 +223,7 @@ export class SettingsDocument { if (location.path.length === 1 && location.previousNode && typeof location.previousNode.value === 'string' && location.previousNode.value.startsWith('[')) { // Suggestion model word matching includes closed sqaure bracket and ending quote // Hence include them in the proposal to replace - let range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position); + const range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position); return this.provideLanguageCompletionItemsForLanguageOverrides(location, range, language => `"[${language}]"`); } return Promise.resolve([]); diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index 4c882c8f8b8..ccbdba90a29 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -10,7 +10,7 @@ "main": "./out/node/cssServerMain", "browser": "./dist/browser/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^4.3.0", + "vscode-css-languageservice": "^4.3.1", "vscode-languageserver": "7.0.0-next.3", "vscode-uri": "^2.1.2" }, diff --git a/extensions/css-language-features/server/test/index.js b/extensions/css-language-features/server/test/index.js index 4e9960494a2..4ab853bd503 100644 --- a/extensions/css-language-features/server/test/index.js +++ b/extensions/css-language-features/server/test/index.js @@ -21,7 +21,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index 26d1a9ecbde..3b9a29250f5 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -696,10 +696,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -vscode-css-languageservice@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.3.0.tgz#40c797d664ab6188cace33cfbb19b037580a9318" - integrity sha512-BkQAMz4oVHjr0oOAz5PdeE72txlLQK7NIwzmclfr+b6fj6I8POwB+VoXvrZLTbWt9hWRgfvgiQRkh5JwrjPJ5A== +vscode-css-languageservice@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.3.1.tgz#a78755b28b8a0cbb1681121f0fa372860f34ef6b" + integrity sha512-Vdz2cyoTP2tLWikhFdouK8dAQ3gVhLPxsFkIscM30Quh6rd/YejTeZEYC/W+b0iKumHYebDeo1GUFbf0ptySRw== dependencies: vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-types "3.16.0-next.2" diff --git a/extensions/debug-auto-launch/package.json b/extensions/debug-auto-launch/package.json index 07568c77081..2e958bb6d25 100644 --- a/extensions/debug-auto-launch/package.json +++ b/extensions/debug-auto-launch/package.json @@ -35,6 +35,12 @@ ], "description": "%debug.node.autoAttach.description%", "default": "disabled" + }, + "debug.javascript.usePreviewAutoAttach": { + "scope": "window", + "type": "boolean", + "default": false, + "description": "%debug.javascript.usePreviewAutoAttach%" } } }, diff --git a/extensions/debug-auto-launch/package.nls.json b/extensions/debug-auto-launch/package.nls.json index 030ac5a20a9..1179563a6c5 100644 --- a/extensions/debug-auto-launch/package.nls.json +++ b/extensions/debug-auto-launch/package.nls.json @@ -3,9 +3,10 @@ "description": "Helper for auto-attach feature when node-debug extensions are not active.", "debug.node.autoAttach.description": "Automatically attach node debugger when node.js was launched in debug mode from integrated terminal.", + "debug.javascript.usePreviewAutoAttach": "Whether to use the preview debugger's version of auto attach.", "debug.node.autoAttach.disabled.description": "Auto attach is disabled and not shown in status bar.", "debug.node.autoAttach.on.description": "Auto attach is active.", "debug.node.autoAttach.off.description": "Auto attach is inactive.", "toggle.auto.attach": "Toggle Auto Attach" -} \ No newline at end of file +} diff --git a/extensions/debug-auto-launch/src/extension.ts b/extensions/debug-auto-launch/src/extension.ts index ef58db6a5ea..4148e1843fe 100644 --- a/extensions/debug-auto-launch/src/extension.ts +++ b/extensions/debug-auto-launch/src/extension.ts @@ -13,10 +13,9 @@ const OFF_TEXT = localize('status.text.auto.attach.off', 'Auto Attach: Off'); const TOGGLE_COMMAND = 'extension.node-debug.toggleAutoAttach'; const JS_DEBUG_SETTINGS = 'debug.javascript'; -const JS_DEBUG_USEPREVIEW = 'usePreview'; +const JS_DEBUG_USEPREVIEWAA = 'usePreviewAutoAttach'; const JS_DEBUG_IPC_KEY = 'jsDebugIpcState'; const NODE_DEBUG_SETTINGS = 'debug.node'; -const NODE_DEBUG_USEV3 = 'useV3'; const AUTO_ATTACH_SETTING = 'autoAttach'; type AUTO_ATTACH_VALUES = 'disabled' | 'on' | 'off'; @@ -38,8 +37,7 @@ export function activate(context: vscode.ExtensionContext): void { // settings that can result in the "state" being changed--on/off/disable or useV3 toggles const effectualConfigurationSettings = [ `${NODE_DEBUG_SETTINGS}.${AUTO_ATTACH_SETTING}`, - `${NODE_DEBUG_SETTINGS}.${NODE_DEBUG_USEV3}`, - `${JS_DEBUG_SETTINGS}.${JS_DEBUG_USEPREVIEW}`, + `${JS_DEBUG_SETTINGS}.${JS_DEBUG_USEPREVIEWAA}`, ]; context.subscriptions.push( @@ -88,6 +86,11 @@ function toggleAutoAttachSetting() { } } +function autoAttachWithJsDebug() { + const jsDebugConfig = vscode.workspace.getConfiguration(JS_DEBUG_SETTINGS); + return jsDebugConfig.get(JS_DEBUG_USEPREVIEWAA, false); +} + function readCurrentState(): State { const nodeConfig = vscode.workspace.getConfiguration(NODE_DEBUG_SETTINGS); const autoAttachState = nodeConfig.get(AUTO_ATTACH_SETTING); @@ -95,11 +98,7 @@ function readCurrentState(): State { case 'off': return State.Off; case 'on': - // todo: reenable after resolving https://github.com/microsoft/vscode/issues/102057 - // const jsDebugConfig = vscode.workspace.getConfiguration(JS_DEBUG_SETTINGS); - // const useV3 = nodeConfig.get(NODE_DEBUG_USEV3) || jsDebugConfig.get(JS_DEBUG_USEPREVIEW); - // return useV3 ? State.OnWithJsDebug : State.OnWithNodeDebug; - return State.OnWithNodeDebug; + return autoAttachWithJsDebug() ? State.OnWithJsDebug : State.OnWithNodeDebug; case 'disabled': default: return State.Disabled; @@ -126,6 +125,11 @@ function ensureStatusBarExists(context: vscode.ExtensionContext) { return statusItem; } +async function clearJsDebugAttachState(context: vscode.ExtensionContext) { + await context.workspaceState.update(JS_DEBUG_IPC_KEY, undefined); + await vscode.commands.executeCommand('extension.js-debug.clearAutoAttachVariables'); +} + interface CachedIpcState { ipcAddress: string; jsDebugPath: string; @@ -144,8 +148,7 @@ const transitions: { [S in State]: StateTransition } = { [State.Disabled]: { async enter(context) { statusItem?.hide(); - await context.workspaceState.update(JS_DEBUG_IPC_KEY, undefined); - await vscode.commands.executeCommand('extension.js-debug.clearAutoAttachVariables'); + await clearJsDebugAttachState(context); }, }, @@ -173,16 +176,24 @@ const transitions: { [S in State]: StateTransition } = { [State.OnWithJsDebug]: { async enter(context) { const ipcAddress = await getIpcAddress(context); + if (!ipcAddress) { + return { context }; + } + const server = await new Promise((resolve, reject) => { const s = createServer((socket) => { let data: Buffer[] = []; socket.on('data', (chunk) => data.push(chunk)); - socket.on('end', () => - vscode.commands.executeCommand( - 'extension.js-debug.autoAttachToProcess', - JSON.parse(Buffer.concat(data).toString()) - ) - ); + socket.on('end', async () => { + try { + await vscode.commands.executeCommand( + 'extension.js-debug.autoAttachToProcess', + JSON.parse(Buffer.concat(data).toString()) + ); + } catch (err) { + console.error(err); + } + }); }) .on('error', reject) .listen(ipcAddress, () => resolve(s)); @@ -190,14 +201,21 @@ const transitions: { [S in State]: StateTransition } = { const statusItem = ensureStatusBarExists(context); statusItem.text = ON_TEXT; - return server; + return { server, context }; }, - async exit(server: Server) { + async exit({ server, context }: { server?: Server, context: vscode.ExtensionContext }) { // we don't need to clear the environment variables--the bootloader will // no-op if the debug server is closed. This prevents having to reload // terminals if users want to turn it back on. - await new Promise((resolve) => server.close(resolve)); + if (server) { + await new Promise((resolve) => server.close(resolve)); + } + + // but if they toggled auto attach use js-debug off, go ahead and do so + if (!autoAttachWithJsDebug()) { + await clearJsDebugAttachState(context); + } }, }, }; @@ -244,8 +262,11 @@ async function getIpcAddress(context: vscode.ExtensionContext) { const result = await vscode.commands.executeCommand<{ ipcAddress: string; }>( 'extension.js-debug.setAutoAttachVariables' ); + if (!result) { + return; + } - const ipcAddress = result!.ipcAddress; + const ipcAddress = result.ipcAddress; await context.workspaceState.update(JS_DEBUG_IPC_KEY, { ipcAddress, jsDebugPath }); return ipcAddress; } diff --git a/extensions/docker/package.json b/extensions/docker/package.json index c1b91dc283d..3af7727a6b4 100644 --- a/extensions/docker/package.json +++ b/extensions/docker/package.json @@ -14,6 +14,7 @@ "id": "dockerfile", "extensions": [ ".dockerfile", ".containerfile" ], "filenames": [ "Dockerfile", "Containerfile" ], + "filenamePatterns": [ "Dockerfile.*", "Containerfile.*" ], "aliases": [ "Dockerfile", "Containerfile" ], "configuration": "./language-configuration.json" }], diff --git a/extensions/emmet/.vscodeignore b/extensions/emmet/.vscodeignore index 573d91ebe6b..8180a27356e 100644 --- a/extensions/emmet/.vscodeignore +++ b/extensions/emmet/.vscodeignore @@ -3,7 +3,8 @@ src/** out/** tsconfig.json extension.webpack.config.js +extension-browser.webpack.config.js CONTRIBUTING.md cgmanifest.json yarn.lock -.vscode \ No newline at end of file +.vscode diff --git a/extensions/emmet/extension.webpack.config.js b/extensions/emmet/extension.webpack.config.js index 96ada4c23a7..bfac2b59f47 100644 --- a/extensions/emmet/extension.webpack.config.js +++ b/extensions/emmet/extension.webpack.config.js @@ -21,6 +21,6 @@ module.exports = withDefaults({ filename: 'emmetNodeMain.js' }, externals: { - 'vscode-emmet-helper2': 'commonjs vscode-emmet-helper2', + 'vscode-emmet-helper': 'commonjs vscode-emmet-helper', }, }); diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index aadbba7edea..d02c19a78ac 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -422,7 +422,7 @@ "scripts": { "watch": "gulp watch-extension:emmet", "compile": "gulp compile-extension:emmet", - "deps": "yarn add vscode-emmet-helper2" + "deps": "yarn add vscode-emmet-helper" }, "devDependencies": { "@types/node": "^12.11.7", @@ -435,7 +435,7 @@ "@emmetio/html-matcher": "^0.3.3", "@emmetio/math-expression": "^0.1.1", "image-size": "^0.5.2", - "vscode-emmet-helper2": "^2.0.0-next.0", + "vscode-emmet-helper": "^2.0.0", "vscode-html-languageservice": "^3.0.3" } } diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index 367f4de2e9d..aa1d2563dbf 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -606,6 +606,25 @@ function expandAbbreviationInRange(editor: vscode.TextEditor, expandAbbrList: Ex return Promise.resolve(false); } +/* +* Walks the tree rooted at root and apply function fn on each node. +* if fn return false at any node, the further processing of tree is stopped. +*/ +function walk(root: any, fn: ((node: any) => boolean)): boolean { + let ctx = root; + while (ctx) { + + let next = ctx.next; + if (fn(ctx) === false || walk(ctx.firstChild, fn) === false) { + return false; + } + + ctx = next; + } + + return true; +} + /** * Expands abbreviation as detailed in given input. */ @@ -648,6 +667,18 @@ function expandAbbr(input: ExpandAbbreviationInput): string | undefined { wrappingNode.value = '\n\t' + wrappingNode.value + '\n'; } } + + // Below fixes https://github.com/microsoft/vscode/issues/78219 + // walk the tree and remove tags for empty values + walk(parsedAbbr, node => { + if (node.name !== null && node.value === '' && !node.isSelfClosing && node.children.length === 0) { + node.name = ''; + node.value = '\n'; + } + + return true; + }); + expandedText = helper.expandAbbreviation(parsedAbbr, expandOptions); // All $anyword would have been escaped by the emmet helper. // Remove the escaping backslash from $TM_SELECTED_TEXT so that VS Code Snippet controller can treat it as a variable diff --git a/extensions/emmet/src/test/index.ts b/extensions/emmet/src/test/index.ts index f3aeb0fefc1..dc77f1beb82 100644 --- a/extensions/emmet/src/test/index.ts +++ b/extensions/emmet/src/test/index.ts @@ -20,7 +20,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts index 0dc2a0e201d..8ef33e97a83 100644 --- a/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -8,7 +8,7 @@ import parse from '@emmetio/html-matcher'; import parseStylesheet from '@emmetio/css-parser'; import { Node, HtmlNode, CssToken, Property, Rule, Stylesheet } from 'EmmetNode'; import { DocumentStreamReader } from './bufferStream'; -import * as EmmetHelper from 'vscode-emmet-helper2'; +import * as EmmetHelper from 'vscode-emmet-helper'; import { TextDocument as LSTextDocument } from 'vscode-html-languageservice'; let _emmetHelper: typeof EmmetHelper; @@ -26,7 +26,7 @@ export function getEmmetHelper() { // Lazy load vscode-emmet-helper instead of importing it // directly to reduce the start-up time of the extension if (!_emmetHelper) { - _emmetHelper = require('vscode-emmet-helper2'); + _emmetHelper = require('vscode-emmet-helper'); } updateEmmetExtensionsPath(); return _emmetHelper; diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index 06a8845658c..cd26963d81b 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -2469,10 +2469,10 @@ vinyl@~2.0.1: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" -vscode-emmet-helper2@^2.0.0-next.0: - version "2.0.0-next.0" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper2/-/vscode-emmet-helper2-2.0.0-next.0.tgz#86eb4c2e581a577e7eb56a51f662e72fb1c63b47" - integrity sha512-ccm6Fb5dkbdEDNLIAebWwVcb8X3AXZDsACLi4KYdCxyFSMV+pOoNokBf4rsu+rSYWNe+fMqxjXZs9z0G2CxPGg== +vscode-emmet-helper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.0.0.tgz#0057ec2d4af8ac83b1f7937383714ffdc56fcc07" + integrity sha512-ytR+Ajxs6zeYI0b4bPsl+nPU8xm852piJUtIwO1ajp1Pw7lwn3VeR+f4ynmxOl9IjfOdF2kW9T/qIkeFbKLwYw== dependencies: "@emmetio/extract-abbreviation" "^0.2.0" jsonc-parser "^2.3.0" diff --git a/extensions/extension-editing/.vscodeignore b/extensions/extension-editing/.vscodeignore index 9d384dd9061..de8e6dc5913 100644 --- a/extensions/extension-editing/.vscodeignore +++ b/extensions/extension-editing/.vscodeignore @@ -3,4 +3,5 @@ src/** tsconfig.json out/** extension.webpack.config.js -yarn.lock \ No newline at end of file +extension-browser.webpack.config.js +yarn.lock diff --git a/extensions/git/package.json b/extensions/git/package.json index d9df45a10b6..748868778dd 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -753,149 +753,49 @@ "group": "navigation", "when": "scmProvider == git" }, - { - "command": "git.sync", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.syncRebase", - "group": "1_sync", - "when": "scmProvider == git && gitState == idle" - }, - { - "command": "git.pull", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.pullRebase", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.pullFrom", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.push", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.pushForce", - "group": "1_sync", - "when": "scmProvider == git && config.git.allowForcePush" - }, - { - "command": "git.pushTo", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.pushToForce", - "group": "1_sync", - "when": "scmProvider == git && config.git.allowForcePush" - }, { "command": "git.checkout", - "group": "2_branch", + "group": "1_header", "when": "scmProvider == git" }, { - "command": "git.publish", - "group": "2_branch", + "command": "git.clone", + "group": "1_header", "when": "scmProvider == git" }, { - "command": "git.commitStaged", - "group": "4_commit", + "submenu": "git.commit", + "group": "2_main@1", "when": "scmProvider == git" }, { - "command": "git.commitStagedSigned", - "group": "4_commit", + "submenu": "git.changes", + "group": "2_main@2", "when": "scmProvider == git" }, { - "command": "git.commitStagedAmend", - "group": "4_commit", + "submenu": "git.pullpush", + "group": "2_main@3", "when": "scmProvider == git" }, { - "command": "git.commitAll", - "group": "4_commit", + "submenu": "git.branch", + "group": "2_main@4", "when": "scmProvider == git" }, { - "command": "git.commitAllSigned", - "group": "4_commit", + "submenu": "git.remotes", + "group": "2_main@5", "when": "scmProvider == git" }, { - "command": "git.commitAllAmend", - "group": "4_commit", - "when": "scmProvider == git" - }, - { - "command": "git.undoCommit", - "group": "4_commit", - "when": "scmProvider == git" - }, - { - "command": "git.stageAll", - "group": "5_stage", - "when": "scmProvider == git" - }, - { - "command": "git.unstageAll", - "group": "5_stage", - "when": "scmProvider == git" - }, - { - "command": "git.cleanAll", - "group": "5_stage", - "when": "scmProvider == git" - }, - { - "command": "git.stashIncludeUntracked", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stash", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashPop", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashPopLatest", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashApply", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashApplyLatest", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashDrop", - "group": "6_stash", + "submenu": "git.stash", + "group": "2_main@6", "when": "scmProvider == git" }, { "command": "git.showOutput", - "group": "7_repository", + "group": "3_footer", "when": "scmProvider == git" } ], @@ -1307,8 +1207,184 @@ "group": "5_copy@2", "when": "config.git.enabled && !git.missing && timelineItem =~ /git:file:commit\\b/" } + ], + "git.commit": [ + { + "command": "git.commit", + "group": "1_commit@1" + }, + { + "command": "git.commitStaged", + "group": "1_commit@2" + }, + { + "command": "git.commitAll", + "group": "1_commit@3" + }, + { + "command": "git.undoCommit", + "group": "1_commit@4" + }, + { + "command": "git.rebaseAbort", + "group": "1_commit@5" + }, + { + "command": "git.commitStagedAmend", + "group": "2_amend@1" + }, + { + "command": "git.commitAllAmend", + "group": "2_amend@1" + }, + { + "command": "git.commitStagedSigned", + "group": "3_signoff@1" + }, + { + "command": "git.commitAllSigned", + "group": "3_signoff@2" + } + ], + "git.changes": [ + { + "command": "git.stageAll" + }, + { + "command": "git.unstageAll" + }, + { + "command": "git.cleanAll" + } + ], + "git.pullpush": [ + { + "command": "git.sync", + "group": "1_sync" + }, + { + "command": "git.syncRebase", + "when": "gitState == idle", + "group": "1_sync" + }, + { + "command": "git.pull", + "group": "2_pull" + }, + { + "command": "git.pullRebase", + "group": "2_pull" + }, + { + "command": "git.pullFrom", + "group": "2_pull" + }, + { + "command": "git.push", + "group": "3_push" + }, + { + "command": "git.pushForce", + "when": "config.git.allowForcePush", + "group": "3_push" + }, + { + "command": "git.pushTo", + "group": "3_push" + }, + { + "command": "git.pushToForce", + "when": "config.git.allowForcePush", + "group": "3_push" + }, + { + "command": "git.fetch", + "group": "4_fetch" + }, + { + "command": "git.fetchPrune", + "group": "4_fetch" + }, + { + "command": "git.fetchAll", + "group": "4_fetch" + } + ], + "git.branch": [ + { + "command": "git.merge" + }, + { + "command": "git.branch" + }, + { + "command": "git.branchFrom" + }, + { + "command": "git.renameBranch" + }, + { + "command": "git.publish" + } + ], + "git.remotes": [ + { + "command": "git.addRemote" + }, + { + "command": "git.removeRemote" + } + ], + "git.stash": [ + { + "command": "git.stash" + }, + { + "command": "git.stashIncludeUntracked" + }, + { + "command": "git.stashApplyLatest" + }, + { + "command": "git.stashApply" + }, + { + "command": "git.stashPopLatest" + }, + { + "command": "git.stashPop" + }, + { + "command": "git.stashDrop" + } ] }, + "submenus": [ + { + "id": "git.commit", + "label": "%submenu.commit%" + }, + { + "id": "git.changes", + "label": "%submenu.changes%" + }, + { + "id": "git.pullpush", + "label": "%submenu.pullpush%" + }, + { + "id": "git.branch", + "label": "%submenu.branch%" + }, + { + "id": "git.remotes", + "label": "%submenu.remotes%" + }, + { + "id": "git.stash", + "label": "%submenu.stash%" + } + ], "configuration": { "title": "Git", "properties": { @@ -1425,6 +1501,11 @@ "description": "%config.ignoreMissingGitWarning%", "default": false }, + "git.ignoreWindowsGit27Warning": { + "type": "boolean", + "description": "%config.ignoreWindowsGit27Warning%", + "default": false + }, "git.ignoreLimitWarning": { "type": "boolean", "description": "%config.ignoreLimitWarning%", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index be817e22df1..0e8ea1c649e 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -99,6 +99,7 @@ "config.branchWhitespaceChar": "The character to replace whitespace in new branch names.", "config.ignoreLegacyWarning": "Ignores the legacy Git warning.", "config.ignoreMissingGitWarning": "Ignores the warning when Git is missing.", + "config.ignoreWindowsGit27Warning": "Ignores the warning when Git 2.25 - 2.26 is installed on Windows.", "config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository.", "config.defaultCloneDirectory": "The default location to clone a git repository.", "config.enableSmartCommit": "Commit all changes when there are no staged changes.", @@ -147,6 +148,14 @@ "config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.", "config.showCommitInput": "Controls whether to show the commit input in the Git source control panel.", "config.terminalAuthentication": "Controls whether to enable VS Code to be the authentication handler for git processes spawned in the integrated terminal. Note: terminals need to be restarted to pick up a change in this setting.", + "submenu.commit": "Commit", + "submenu.commit.amend": "Amend", + "submenu.commit.signoff": "Sign Off", + "submenu.changes": "Changes", + "submenu.pullpush": "Pull, Push", + "submenu.branch": "Branch", + "submenu.remotes": "Remote", + "submenu.stash": "Stash", "colors.added": "Color for added resources.", "colors.modified": "Color for modified resources.", "colors.deleted": "Color for deleted resources.", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index c9fe2503d22..f618a8669c2 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -543,11 +543,11 @@ export class CommandCenter { const uri = Uri.file(repositoryPath); if (openFolder) { - commands.executeCommand('vscode.openFolder', uri); + commands.executeCommand('vscode.openFolder', uri, { forceReuseWindow: true }); } else if (result === addToWorkspace) { workspace.updateWorkspaceFolders(workspace.workspaceFolders!.length, 0, { uri }); } else if (result === openNewWindow) { - commands.executeCommand('vscode.openFolder', uri, true); + commands.executeCommand('vscode.openFolder', uri, { forceNewWindow: true }); } } catch (err) { if (/already exists and is not an empty directory/.test(err && err.stderr || '')) { diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index cabcce04413..8bf85a1b3ee 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -208,14 +208,25 @@ async function checkGitWindows(info: IGit): Promise { return; } + const config = workspace.getConfiguration('git'); + const shouldIgnore = config.get('ignoreWindowsGit27Warning') === true; + + if (shouldIgnore) { + return; + } + const update = localize('updateGit', "Update Git"); + const neverShowAgain = localize('neverShowAgain', "Don't Show Again"); const choice = await window.showWarningMessage( localize('git2526', "There are known issues with the installed Git {0}. Please update to Git >= 2.27 for the git features to work correctly.", info.version), - update + update, + neverShowAgain ); if (choice === update) { commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/')); + } else if (choice === neverShowAgain) { + await config.update('ignoreWindowsGit27Warning', true, true); } } diff --git a/extensions/git/src/statusbar.ts b/extensions/git/src/statusbar.ts index 760a507a8f9..8a108ae1b45 100644 --- a/extensions/git/src/statusbar.ts +++ b/extensions/git/src/statusbar.ts @@ -61,6 +61,15 @@ class SyncStatusBar { } constructor(private repository: Repository, private remoteSourceProviderRegistry: IRemoteSourceProviderRegistry) { + this._state = { + enabled: true, + isSyncRunning: false, + hasRemotes: false, + HEAD: undefined, + remoteSourceProviders: this.remoteSourceProviderRegistry.getRemoteProviders() + .filter(p => !!p.publishRepository) + }; + repository.onDidRunGitStatus(this.onDidRunGitStatus, this, this.disposables); repository.onDidChangeOperations(this.onDidChangeOperations, this, this.disposables); @@ -70,15 +79,6 @@ class SyncStatusBar { const onEnablementChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.enableStatusBarSync')); onEnablementChange(this.updateEnablement, this, this.disposables); this.updateEnablement(); - - this._state = { - enabled: true, - isSyncRunning: false, - hasRemotes: false, - HEAD: undefined, - remoteSourceProviders: this.remoteSourceProviderRegistry.getRemoteProviders() - .filter(p => !!p.publishRepository) - }; } private updateEnablement(): void { diff --git a/extensions/git/src/test/index.ts b/extensions/git/src/test/index.ts index 747c4562e8a..a3588b2238c 100644 --- a/extensions/git/src/test/index.ts +++ b/extensions/git/src/test/index.ts @@ -20,7 +20,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/git/src/timelineProvider.ts b/extensions/git/src/timelineProvider.ts index d6e2be8613b..5600b6f0e0c 100644 --- a/extensions/git/src/timelineProvider.ts +++ b/extensions/git/src/timelineProvider.ts @@ -65,27 +65,32 @@ export class GitTimelineProvider implements TimelineProvider { readonly id = 'git-history'; readonly label = localize('git.timeline.source', 'Git History'); - private disposable: Disposable; + private readonly disposable: Disposable; + private providerDisposable: Disposable | undefined; private repo: Repository | undefined; private repoDisposable: Disposable | undefined; private repoStatusDate: Date | undefined; - constructor(private readonly _model: Model) { + constructor(private readonly model: Model) { this.disposable = Disposable.from( - _model.onDidOpenRepository(this.onRepositoriesChanged, this), - workspace.registerTimelineProvider(['file', 'git', 'vscode-remote', 'gitlens-git'], this), + model.onDidOpenRepository(this.onRepositoriesChanged, this), ); + + if (model.repositories.length) { + this.ensureProviderRegistration(); + } } dispose() { + this.providerDisposable?.dispose(); this.disposable.dispose(); } async provideTimeline(uri: Uri, options: TimelineOptions, _token: CancellationToken): Promise { // console.log(`GitTimelineProvider.provideTimeline: uri=${uri} state=${this._model.state}`); - const repo = this._model.getRepository(uri); + const repo = this.model.getRepository(uri); if (!repo) { this.repoDisposable?.dispose(); this.repoStatusDate = undefined; @@ -110,7 +115,7 @@ export class GitTimelineProvider implements TimelineProvider { let limit: number | undefined; if (options.limit !== undefined && typeof options.limit !== 'number') { try { - const result = await this._model.git.exec(repo.root, ['rev-list', '--count', `${options.limit.id}..`, '--', uri.fsPath]); + const result = await this.model.git.exec(repo.root, ['rev-list', '--count', `${options.limit.id}..`, '--', uri.fsPath]); if (!result.exitCode) { // Ask for 2 more (1 for the limit commit and 1 for the next commit) than so we can determine if there are more commits limit = Number(result.stdout) + 2; @@ -203,9 +208,17 @@ export class GitTimelineProvider implements TimelineProvider { }; } + private ensureProviderRegistration() { + if (this.providerDisposable === undefined) { + this.providerDisposable = workspace.registerTimelineProvider(['file', 'git', 'vscode-remote', 'gitlens-git'], this); + } + } + private onRepositoriesChanged(_repo: Repository) { // console.log(`GitTimelineProvider.onRepositoriesChanged`); + this.ensureProviderRegistration(); + // TODO@eamodio: Being naive for now and just always refreshing each time there is a new repository this.fireChanged(); } diff --git a/extensions/github-authentication/.vscodeignore b/extensions/github-authentication/.vscodeignore index ee85b884502..5f3350adfb6 100644 --- a/extensions/github-authentication/.vscodeignore +++ b/extensions/github-authentication/.vscodeignore @@ -1,8 +1,10 @@ +.gitignore src/** !src/common/config.json out/** build/** extension.webpack.config.js +extension-browser.webpack.config.js tsconfig.json yarn.lock README.md diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index c4189e6b7eb..8136ebd04ca 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -15,6 +15,11 @@ "*", "onAuthenticationRequest:github" ], + "extensionKind": [ + "ui", + "workspace", + "web" + ], "contributes": { "commands": [ { diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index 0f9284bbecf..a042ebe2a36 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -9,7 +9,7 @@ import { keychain } from './common/keychain'; import { GitHubServer, NETWORK_ERROR } from './githubServer'; import Logger from './common/logger'; -export const onDidChangeSessions = new vscode.EventEmitter(); +export const onDidChangeSessions = new vscode.EventEmitter(); interface SessionData { id: string; diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts index fcae1cf9a14..aa7dec8e9b4 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -79,7 +79,7 @@ export class GitHubServer { const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`)); if (this.isTestEnvironment(callbackUri)) { - const token = await vscode.window.showInputBox({ prompt: 'Token', ignoreFocusOut: true }); + const token = await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true }); if (!token) { throw new Error('Sign in failed: No token provided'); } this.updateStatusBarItem(false); return token; diff --git a/extensions/github-browser/.gitignore b/extensions/github-browser/.gitignore deleted file mode 100644 index c19bd94aaa7..00000000000 --- a/extensions/github-browser/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -dist -out -node_modules diff --git a/extensions/github-browser/.vscodeignore b/extensions/github-browser/.vscodeignore deleted file mode 100644 index 32fe3f03697..00000000000 --- a/extensions/github-browser/.vscodeignore +++ /dev/null @@ -1,11 +0,0 @@ -.vscode/** -build/** -dist/** -out/** -src/** -typings/** -.gitignore -extension-browser.webpack.config.js -extension.webpack.config.js -tsconfig.json -yarn.lock diff --git a/extensions/github-browser/README.md b/extensions/github-browser/README.md deleted file mode 100644 index ef4d6f58e8b..00000000000 --- a/extensions/github-browser/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# GitHub FileSystem for Visual Studio Code - -**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. - -## Features - -This extension provides remote GitHub repository features for VS Code. diff --git a/extensions/github-browser/extension-browser.webpack.config.js b/extensions/github-browser/extension-browser.webpack.config.js deleted file mode 100644 index 55f3a268486..00000000000 --- a/extensions/github-browser/extension-browser.webpack.config.js +++ /dev/null @@ -1,25 +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 withBrowserDefaults = require('../shared.webpack.config').browser; - -const config = withBrowserDefaults({ - context: __dirname, - node: false, - entry: { - extension: './src/extension.ts' - }, - resolve: { - alias: { - 'node-fetch': path.resolve(__dirname, 'node_modules/node-fetch/browser.js') - } - } -}); - -module.exports = config; diff --git a/extensions/github-browser/package.json b/extensions/github-browser/package.json deleted file mode 100644 index 9938e25ed54..00000000000 --- a/extensions/github-browser/package.json +++ /dev/null @@ -1,168 +0,0 @@ -{ - "name": "github-browser", - "displayName": "%displayName%", - "description": "%description%", - "publisher": "vscode", - "version": "0.0.1", - "engines": { - "vscode": "^1.45.0" - }, - "enableProposedApi": true, - "private": true, - "categories": [ - "Other" - ], - "activationEvents": [ - "onFileSystem:codespace", - "onFileSystem:github", - "onCommand:githubBrowser.openRepository" - ], - "browser": "./dist/browser/extension.js", - "main": "./out/extension.js", - "contributes": { - "commands": [ - { - "command": "githubBrowser.openRepository", - "title": "Open GitHub Repository...", - "category": "GitHub Browser" - }, - { - "command": "githubBrowser.commit", - "title": "Commit", - "icon": "$(check)", - "category": "GitHub Browser" - }, - { - "command": "githubBrowser.discardChanges", - "title": "Discard Changes", - "icon": "$(discard)", - "category": "GitHub Browser" - }, - { - "command": "githubBrowser.openChanges", - "title": "Open Changes", - "icon": "$(git-compare)", - "category": "GitHub Browser" - }, - { - "command": "githubBrowser.openFile", - "title": "Open File", - "icon": "$(go-to-file)", - "category": "GitHub Browser" - } - ], - "menus": { - "commandPalette": [ - { - "command": "githubBrowser.openRepository", - "when": "config.githubBrowser.openRepository" - }, - { - "command": "githubBrowser.commit", - "when": "false" - }, - { - "command": "githubBrowser.discardChanges", - "when": "false" - }, - { - "command": "githubBrowser.openChanges", - "when": "false" - }, - { - "command": "githubBrowser.openFile", - "when": "false" - } - ], - "scm/title": [ - { - "command": "githubBrowser.commit", - "group": "navigation", - "when": "scmProvider == github" - } - ], - "scm/resourceState/context": [ - { - "command": "githubBrowser.openFile", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "inline@0" - }, - { - "command": "githubBrowser.discardChanges", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "inline@1" - }, - { - "command": "githubBrowser.openChanges", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "navigation@0" - }, - { - "command": "githubBrowser.openFile", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "navigation@1" - }, - { - "command": "githubBrowser.discardChanges", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "1_modification@0" - } - ] - }, - "resourceLabelFormatters": [ - { - "scheme": "github", - "authority": "HEAD", - "formatting": { - "label": "github.com${path}", - "separator": "/", - "workspaceSuffix": "GitHub" - } - }, - { - "scheme": "github", - "authority": "*", - "formatting": { - "label": "github.com${path} (${authority})", - "separator": "/", - "workspaceSuffix": "GitHub" - } - }, - { - "scheme": "codespace", - "authority": "HEAD", - "formatting": { - "label": "github.com${path}", - "separator": "/", - "workspaceSuffix": "GitHub" - } - }, - { - "scheme": "codespace", - "authority": "*", - "formatting": { - "label": "github.com${path} (${authority})", - "separator": "/", - "workspaceSuffix": "GitHub" - } - } - ] - }, - "scripts": { - "compile": "gulp compile-extension:github-browser", - "compile-web": "npx webpack-cli --config extension-browser.webpack.config --mode none", - "watch": "gulp watch-extension:github-browser", - "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose", - "vscode:prepublish": "npm run compile" - }, - "dependencies": { - "@octokit/graphql": "4.5.1", - "@octokit/rest": "18.0.0", - "fuzzysort": "1.1.4", - "node-fetch": "2.6.0", - "vscode-nls": "4.1.2" - }, - "devDependencies": { - "@types/node-fetch": "2.5.7" - } -} diff --git a/extensions/github-browser/package.nls.json b/extensions/github-browser/package.nls.json deleted file mode 100644 index 69f0f911776..00000000000 --- a/extensions/github-browser/package.nls.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "displayName": "GitHub Browser", - "description": "Remotely browse a GitHub repository" -} diff --git a/extensions/github-browser/src/changeStore.ts b/extensions/github-browser/src/changeStore.ts deleted file mode 100644 index f4bd624b9e7..00000000000 --- a/extensions/github-browser/src/changeStore.ts +++ /dev/null @@ -1,380 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { commands, Event, EventEmitter, FileStat, FileType, Memento, TextDocumentShowOptions, Uri, ViewColumn } from 'vscode'; -import { getRootUri, getRelativePath, isChild } from './extension'; -import { sha1 } from './sha1'; - -const textDecoder = new TextDecoder(); - -interface CreateOperation { - type: 'created'; - size: number; - timestamp: number; - uri: T; - hash: string; - originalHash: string; -} - -interface ChangeOperation { - type: 'changed'; - size: number; - timestamp: number; - uri: T; - hash: string; - originalHash: string; -} - -interface DeleteOperation { - type: 'deleted'; - size: undefined; - timestamp: number; - uri: T; - hash: undefined; - originalHash: undefined; -} - -export type Operation = CreateOperation | ChangeOperation | DeleteOperation; -type StoredOperation = CreateOperation | ChangeOperation | DeleteOperation; - -const workingOperationsKeyPrefix = 'github.working.changes|'; -const workingFileKeyPrefix = 'github.working|'; - -function fromSerialized(operations: StoredOperation): Operation { - return { ...operations, uri: Uri.parse(operations.uri) }; -} - -export interface ChangeStoreEvent { - type: 'created' | 'changed' | 'deleted'; - rootUri: Uri; - uri: Uri; -} - -function toChangeStoreEvent(operation: Operation | StoredOperation, rootUri: Uri, uri?: Uri): ChangeStoreEvent { - return { - type: operation.type, - rootUri: rootUri, - uri: uri ?? (typeof operation.uri === 'string' ? Uri.parse(operation.uri) : operation.uri), - }; -} - -export interface IChangeStore { - onDidChange: Event; - - acceptAll(rootUri: Uri): Promise; - discard(uri: Uri): Promise; - discardAll(rootUri: Uri): Promise; - - hasChanges(rootUri: Uri): boolean; - - getChanges(rootUri: Uri): Operation[]; - getContent(uri: Uri): string | undefined; - - openChanges(uri: Uri, original: Uri): void; - openFile(uri: Uri): void; -} - -export interface IWritableChangeStore { - onDidChange: Event; - - hasChanges(rootUri: Uri): boolean; - - getContent(uri: Uri): string | undefined; - getStat(uri: Uri): FileStat | undefined; - updateDirectoryEntries(uri: Uri, entries: [string, FileType][]): [string, FileType][]; - - onFileChanged(uri: Uri, content: Uint8Array, originalContent: () => Uint8Array | Thenable): Promise; - onFileCreated(uri: Uri, content: Uint8Array): Promise; - onFileDeleted(uri: Uri): Promise; -} - -export class ChangeStore implements IChangeStore, IWritableChangeStore { - private _onDidChange = new EventEmitter(); - get onDidChange(): Event { - return this._onDidChange.event; - } - - constructor(private readonly memento: Memento) { } - - async acceptAll(rootUri: Uri): Promise { - const operations = this.getChanges(rootUri); - - await this.saveWorkingOperations(rootUri, undefined); - - const events: ChangeStoreEvent[] = []; - - for (const operation of operations) { - await this.discardWorkingContent(operation.uri); - events.push(toChangeStoreEvent(operation, rootUri)); - } - - for (const e of events) { - this._onDidChange.fire(e); - } - } - - async discard(uri: Uri): Promise { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return; - } - - const key = uri.toString(); - - const operations = this.getWorkingOperations(rootUri); - const index = operations.findIndex(c => c.uri === key); - if (index === -1) { - return; - } - - const [operation] = operations.splice(index, 1); - await this.saveWorkingOperations(rootUri, operations); - await this.discardWorkingContent(uri); - - this._onDidChange.fire({ - type: operation.type === 'created' ? 'deleted' : operation.type === 'deleted' ? 'created' : 'changed', - rootUri: rootUri, - uri: uri, - }); - } - - async discardAll(rootUri: Uri): Promise { - const operations = this.getChanges(rootUri); - - await this.saveWorkingOperations(rootUri, undefined); - - const events: ChangeStoreEvent[] = []; - - for (const operation of operations) { - await this.discardWorkingContent(operation.uri); - events.push(toChangeStoreEvent(operation, rootUri)); - } - - for (const e of events) { - this._onDidChange.fire(e); - } - } - - getChanges(rootUri: Uri) { - return this.getWorkingOperations(rootUri).map(c => fromSerialized(c)); - } - - getContent(uri: Uri): string | undefined { - return this.memento.get(`${workingFileKeyPrefix}${uri.toString()}`); - } - - getStat(uri: Uri): FileStat | undefined { - const key = uri.toString(); - const operation = this.getChanges(getRootUri(uri)!).find(c => c.uri.toString() === key); - if (operation === undefined) { - return undefined; - } - - return { - type: FileType.File, - size: operation.size ?? 0, - ctime: 0, - mtime: operation.timestamp - }; - } - - hasChanges(rootUri: Uri): boolean { - return this.getWorkingOperations(rootUri).length !== 0; - } - - updateDirectoryEntries(uri: Uri, entries: [string, FileType][]): [string, FileType][] { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return entries; - } - - const folderPath = getRelativePath(rootUri, uri); - - const operations = this.getChanges(rootUri); - for (const operation of operations) { - switch (operation.type) { - case 'changed': - continue; - - case 'created': { - const filePath = getRelativePath(rootUri, operation.uri); - if (isChild(folderPath, filePath)) { - entries.push([filePath, FileType.File]); - } - break; - } - - case 'deleted': { - const filePath = getRelativePath(rootUri, operation.uri); - if (isChild(folderPath, filePath)) { - const index = entries.findIndex(([path]) => path === filePath); - if (index !== -1) { - entries.splice(index, 1); - } - } - break; - } - } - } - - return entries; - } - - async onFileChanged(uri: Uri, content: Uint8Array, originalContent: () => Uint8Array | Thenable): Promise { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return; - } - - const key = uri.toString(); - - const operations = this.getWorkingOperations(rootUri); - - const hash = await sha1(content); - - let operation = operations.find(c => c.uri === key); - if (operation === undefined) { - const originalHash = await sha1(await originalContent!()); - if (hash === originalHash) { - return; - } - - operation = { - type: 'changed', - size: content.byteLength, - timestamp: Date.now(), - uri: key, - hash: hash!, - originalHash: originalHash - } as ChangeOperation; - operations.push(operation); - - await this.saveWorkingOperations(rootUri, operations); - await this.saveWorkingContent(uri, textDecoder.decode(content)); - } else if (hash! === operation.originalHash) { - operations.splice(operations.indexOf(operation), 1); - - await this.saveWorkingOperations(rootUri, operations); - await this.discardWorkingContent(uri); - } else if (operation.hash !== hash) { - operation.hash = hash!; - operation.timestamp = Date.now(); - - await this.saveWorkingOperations(rootUri, operations); - await this.saveWorkingContent(uri, textDecoder.decode(content)); - } - - this._onDidChange.fire(toChangeStoreEvent(operation, rootUri, uri)); - } - - async onFileCreated(uri: Uri, content: Uint8Array): Promise { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return; - } - - const key = uri.toString(); - - const operations = this.getWorkingOperations(rootUri); - - const hash = await sha1(content); - - let operation = operations.find(c => c.uri === key); - if (operation === undefined) { - operation = { - type: 'created', - size: content.byteLength, - timestamp: Date.now(), - uri: key, - hash: hash!, - originalHash: hash! - } as CreateOperation; - operations.push(operation); - - await this.saveWorkingOperations(rootUri, operations); - await this.saveWorkingContent(uri, textDecoder.decode(content)); - } else { - // Shouldn't happen, but if it does just update the contents - operation.hash = hash!; - operation.timestamp = Date.now(); - - await this.saveWorkingOperations(rootUri, operations); - await this.saveWorkingContent(uri, textDecoder.decode(content)); - } - - this._onDidChange.fire(toChangeStoreEvent(operation, rootUri, uri)); - } - - async onFileDeleted(uri: Uri): Promise { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return; - } - - const key = uri.toString(); - - const operations = this.getWorkingOperations(rootUri); - - let operation = operations.find(c => c.uri === key); - if (operation !== undefined) { - operations.splice(operations.indexOf(operation), 1); - } - - const wasCreated = operation?.type === 'created'; - - operation = { - type: 'deleted', - timestamp: Date.now(), - uri: key, - } as DeleteOperation; - - // Only track the delete, if we weren't tracking the create - if (!wasCreated) { - operations.push(operation); - } - - await this.saveWorkingOperations(rootUri, operations); - await this.discardWorkingContent(uri); - - this._onDidChange.fire(toChangeStoreEvent(operation, rootUri, uri)); - } - - async openChanges(uri: Uri, original: Uri) { - const opts: TextDocumentShowOptions = { - preserveFocus: false, - preview: true, - viewColumn: ViewColumn.Active - }; - - await commands.executeCommand('vscode.diff', original, uri, `${uri.fsPath} (Working Tree)`, opts); - } - - async openFile(uri: Uri) { - const opts: TextDocumentShowOptions = { - preserveFocus: false, - preview: false, - viewColumn: ViewColumn.Active - }; - - await commands.executeCommand('vscode.open', uri, opts); - } - - private getWorkingOperations(rootUri: Uri): StoredOperation[] { - return this.memento.get(`${workingOperationsKeyPrefix}${rootUri.toString()}`, []); - } - - private async saveWorkingOperations(rootUri: Uri, operations: StoredOperation[] | undefined): Promise { - await this.memento.update(`${workingOperationsKeyPrefix}${rootUri.toString()}`, operations); - } - - private async saveWorkingContent(uri: Uri, content: string): Promise { - await this.memento.update(`${workingFileKeyPrefix}${uri.toString()}`, content); - } - - private async discardWorkingContent(uri: Uri): Promise { - await this.memento.update(`${workingFileKeyPrefix}${uri.toString()}`, undefined); - } -} diff --git a/extensions/github-browser/src/contextStore.ts b/extensions/github-browser/src/contextStore.ts deleted file mode 100644 index 80286445dfe..00000000000 --- a/extensions/github-browser/src/contextStore.ts +++ /dev/null @@ -1,53 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { Event, EventEmitter, Memento, Uri, workspace } from 'vscode'; - -export interface WorkspaceFolderContext { - context: T; - name: string; - folderUri: Uri; -} - -export class ContextStore { - private _onDidChange = new EventEmitter(); - get onDidChange(): Event { - return this._onDidChange.event; - } - - constructor( - private readonly scheme: string, - private readonly originalScheme: string, - private readonly memento: Memento, - ) { } - - delete(uri: Uri) { - return this.set(uri, undefined); - } - - get(uri: Uri): T | undefined { - return this.memento.get(`${this.originalScheme}.context|${this.getOriginalResource(uri).toString()}`); - } - - getForWorkspace(): WorkspaceFolderContext[] { - const folders = workspace.workspaceFolders?.filter(f => f.uri.scheme === this.scheme || f.uri.scheme === this.originalScheme) ?? []; - return folders.map(f => ({ context: this.get(f.uri)!, name: f.name, folderUri: f.uri })).filter(c => c.context !== undefined); - } - - async set(uri: Uri, context: T | undefined) { - uri = this.getOriginalResource(uri); - await this.memento.update(`${this.originalScheme}.context|${uri.toString()}`, context); - this._onDidChange.fire(uri); - } - - getOriginalResource(uri: Uri): Uri { - return uri.with({ scheme: this.originalScheme }); - } - - getWorkspaceResource(uri: Uri): Uri { - return uri.with({ scheme: this.scheme }); - } -} diff --git a/extensions/github-browser/src/extension.ts b/extensions/github-browser/src/extension.ts deleted file mode 100644 index 893daf93c58..00000000000 --- a/extensions/github-browser/src/extension.ts +++ /dev/null @@ -1,80 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { commands, ExtensionContext, Uri, window, workspace } from 'vscode'; -import { ChangeStore } from './changeStore'; -import { ContextStore } from './contextStore'; -import { VirtualFS } from './fs'; -import { GitHubApiContext, GitHubApi } from './github/api'; -import { GitHubFS } from './github/fs'; -import { VirtualSCM } from './scm'; -import { StatusBar } from './statusbar'; - -const repositoryRegex = /^(?:(?:https:\/\/)?github.com\/)?([^\/]+)\/([^\/]+?)(?:\/|.git|$)/i; - -export async function activate(context: ExtensionContext) { - const contextStore = new ContextStore('codespace', GitHubFS.scheme, context.workspaceState); - const changeStore = new ChangeStore(context.workspaceState); - - const githubApi = new GitHubApi(contextStore); - const gitHubFS = new GitHubFS(githubApi); - const virtualFS = new VirtualFS('codespace', contextStore, changeStore, gitHubFS); - - context.subscriptions.push( - githubApi, - gitHubFS, - virtualFS, - new VirtualSCM(GitHubFS.scheme, githubApi, changeStore), - new StatusBar(contextStore, changeStore), - ); - - commands.registerCommand('githubBrowser.openRepository', async () => { - const value = await window.showInputBox({ - placeHolder: 'e.g. https://github.com/microsoft/vscode', - prompt: 'Enter a GitHub repository url', - validateInput: value => repositoryRegex.test(value) ? undefined : 'Invalid repository url' - }); - - if (value) { - const match = repositoryRegex.exec(value); - if (match) { - const [, owner, repo] = match; - - const uri = Uri.parse(`codespace://HEAD/${owner}/${repo}`); - openWorkspace(uri, repo, 'currentWindow'); - } - } - }); -} - -export function getRelativePath(rootUri: Uri, uri: Uri) { - return uri.path.substr(rootUri.path.length + 1); -} - -export function getRootUri(uri: Uri) { - return workspace.getWorkspaceFolder(uri)?.uri; -} - -export function isChild(folderPath: string, filePath: string) { - return isDescendent(folderPath, filePath) && filePath.substr(folderPath.length + (folderPath.endsWith('/') ? 0 : 1)).split('/').length === 1; -} - -export function isDescendent(folderPath: string, filePath: string) { - return folderPath.length === 0 || filePath.startsWith(folderPath.endsWith('/') ? folderPath : `${folderPath}/`); -} - -const shaRegex = /^[0-9a-f]{40}$/; -export function isSha(ref: string) { - return shaRegex.test(ref); -} - -function openWorkspace(uri: Uri, name: string, location: 'currentWindow' | 'newWindow' | 'addToCurrentWorkspace') { - if (location === 'addToCurrentWorkspace') { - const count = (workspace.workspaceFolders && workspace.workspaceFolders.length) || 0; - return workspace.updateWorkspaceFolders(count, 0, { uri: uri, name: name }); - } - - return commands.executeCommand('vscode.openFolder', uri, location === 'newWindow'); -} diff --git a/extensions/github-browser/src/fs.ts b/extensions/github-browser/src/fs.ts deleted file mode 100644 index 56af40f21ba..00000000000 --- a/extensions/github-browser/src/fs.ts +++ /dev/null @@ -1,216 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { - CancellationToken, - Disposable, - Event, - EventEmitter, - FileChangeEvent, - FileChangeType, - FileSearchOptions, - FileSearchProvider, - FileSearchQuery, - FileStat, - FileSystemError, - FileSystemProvider, - FileType, - Progress, - TextSearchOptions, - TextSearchProvider, - TextSearchQuery, - TextSearchResult, - Uri, - workspace, -} from 'vscode'; -import { IWritableChangeStore } from './changeStore'; -import { ContextStore } from './contextStore'; -import { GitHubApiContext } from './github/api'; - -const emptyDisposable = { dispose: () => { /* noop */ } }; -const textEncoder = new TextEncoder(); - -export class VirtualFS implements FileSystemProvider, FileSearchProvider, TextSearchProvider, Disposable { - private _onDidChangeFile = new EventEmitter(); - get onDidChangeFile(): Event { - return this._onDidChangeFile.event; - } - - private readonly disposable: Disposable; - - constructor( - readonly scheme: string, - private readonly contextStore: ContextStore, - private readonly changeStore: IWritableChangeStore, - private readonly fs: FileSystemProvider & FileSearchProvider & TextSearchProvider - ) { - // TODO@eamodio listen for workspace folder changes - for (const context of contextStore.getForWorkspace()) { - // If we have a saved context, but no longer have any changes, reset the context - // We only do this on startup/reload to keep things consistent - if (!changeStore.hasChanges(context.folderUri)) { - console.log('Clear context', context.folderUri.toString()); - contextStore.delete(context.folderUri); - } - } - - this.disposable = Disposable.from( - workspace.registerFileSystemProvider(scheme, this, { isCaseSensitive: true }), - workspace.registerFileSearchProvider(scheme, this), - workspace.registerTextSearchProvider(scheme, this), - changeStore.onDidChange(e => { - switch (e.type) { - case 'created': - this._onDidChangeFile.fire([{ type: FileChangeType.Created, uri: e.uri }]); - break; - case 'changed': - this._onDidChangeFile.fire([{ type: FileChangeType.Changed, uri: e.uri }]); - break; - case 'deleted': - this._onDidChangeFile.fire([{ type: FileChangeType.Deleted, uri: e.uri }]); - break; - } - }), - ); - } - - dispose() { - this.disposable?.dispose(); - } - - private getOriginalResource(uri: Uri): Uri { - return this.contextStore.getOriginalResource(uri); - } - - private getWorkspaceResource(uri: Uri): Uri { - return this.contextStore.getWorkspaceResource(uri); - } - - //#region FileSystemProvider - - watch(): Disposable { - return emptyDisposable; - } - - async stat(uri: Uri): Promise { - let stat = this.changeStore.getStat(uri); - if (stat !== undefined) { - return stat; - } - - stat = await this.fs.stat(this.getOriginalResource(uri)); - return stat; - } - - async readDirectory(uri: Uri): Promise<[string, FileType][]> { - let entries = await this.fs.readDirectory(this.getOriginalResource(uri)); - entries = this.changeStore.updateDirectoryEntries(uri, entries); - return entries; - } - - createDirectory(_uri: Uri): void | Thenable { - // TODO@eamodio only support files for now - throw FileSystemError.NoPermissions(); - } - - async readFile(uri: Uri): Promise { - const content = this.changeStore.getContent(uri); - if (content !== undefined) { - return textEncoder.encode(content); - } - - const data = await this.fs.readFile(this.getOriginalResource(uri)); - return data; - } - - async writeFile(uri: Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): Promise { - let stat; - try { - stat = await this.stat(uri); - if (!options.overwrite) { - throw FileSystemError.FileExists(); - } - } catch (ex) { - if (ex instanceof FileSystemError && ex.code === 'FileNotFound') { - if (!options.create) { - throw FileSystemError.FileNotFound(); - } - } else { - throw ex; - } - } - - if (stat === undefined) { - await this.changeStore.onFileCreated(uri, content); - } else { - await this.changeStore.onFileChanged(uri, content, () => this.fs.readFile(this.getOriginalResource(uri))); - } - } - - async delete(uri: Uri, _options: { recursive: boolean }): Promise { - const stat = await this.stat(uri); - if (stat.type !== FileType.File) { - throw FileSystemError.NoPermissions(); - } - - await this.changeStore.onFileDeleted(uri); - } - - async rename(oldUri: Uri, newUri: Uri, options: { overwrite: boolean }): Promise { - const stat = await this.stat(oldUri); - // TODO@eamodio only support files for now - if (stat.type !== FileType.File) { - throw FileSystemError.NoPermissions(); - } - - const content = await this.readFile(oldUri); - await this.writeFile(newUri, content, { create: true, overwrite: options.overwrite }); - await this.delete(oldUri, { recursive: false }); - } - - async copy(source: Uri, destination: Uri, options: { overwrite: boolean }): Promise { - const stat = await this.stat(source); - // TODO@eamodio only support files for now - if (stat.type !== FileType.File) { - throw FileSystemError.NoPermissions(); - } - - const content = await this.readFile(source); - await this.writeFile(destination, content, { create: true, overwrite: options.overwrite }); - } - - //#endregion - - //#region FileSearchProvider - - provideFileSearchResults( - query: FileSearchQuery, - options: FileSearchOptions, - token: CancellationToken, - ) { - return this.fs.provideFileSearchResults(query, { ...options, folder: this.getOriginalResource(options.folder) }, token); - } - - //#endregion - - //#region TextSearchProvider - - provideTextSearchResults( - query: TextSearchQuery, - options: TextSearchOptions, - progress: Progress, - token: CancellationToken, - ) { - return this.fs.provideTextSearchResults( - query, - { ...options, folder: this.getOriginalResource(options.folder) }, - { report: (result: TextSearchResult) => progress.report({ ...result, uri: this.getWorkspaceResource(result.uri) }) }, - token - ); - } - - //#endregion -} diff --git a/extensions/github-browser/src/gate.ts b/extensions/github-browser/src/gate.ts deleted file mode 100644 index d49762dc748..00000000000 --- a/extensions/github-browser/src/gate.ts +++ /dev/null @@ -1,87 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -const emptyStr = ''; - -function defaultResolver(...args: any[]): string { - if (args.length === 1) { - const arg0 = args[0]; - if (arg0 === undefined || arg0 === null) { - return emptyStr; - } - if (typeof arg0 === 'string') { - return arg0; - } - if (typeof arg0 === 'number' || typeof arg0 === 'boolean') { - return String(arg0); - } - - return JSON.stringify(arg0); - } - - return JSON.stringify(args); -} - -function iPromise(obj: T | Promise): obj is Promise { - return typeof (obj as Promise)?.then === 'function'; -} - -export function gate any>(resolver?: (...args: Parameters) => string) { - return (_target: any, key: string, descriptor: PropertyDescriptor) => { - let fn: Function | undefined; - if (typeof descriptor.value === 'function') { - fn = descriptor.value; - } else if (typeof descriptor.get === 'function') { - fn = descriptor.get; - } - if (fn === undefined || fn === null) { - throw new Error('Not supported'); - } - - const gateKey = `$gate$${key}`; - - descriptor.value = function (this: any, ...args: any[]) { - const prop = - args.length === 0 ? gateKey : `${gateKey}$${(resolver ?? defaultResolver)(...(args as Parameters))}`; - - if (!Object.prototype.hasOwnProperty.call(this, prop)) { - Object.defineProperty(this, prop, { - configurable: false, - enumerable: false, - writable: true, - value: undefined, - }); - } - - let promise = this[prop]; - if (promise === undefined) { - let result; - try { - result = fn!.apply(this, args); - if (result === undefined || fn === null || !iPromise(result)) { - return result; - } - - this[prop] = promise = result - .then((r: any) => { - this[prop] = undefined; - return r; - }) - .catch(ex => { - this[prop] = undefined; - throw ex; - }); - } catch (ex) { - this[prop] = undefined; - throw ex; - } - } - - return promise; - }; - }; -} diff --git a/extensions/github-browser/src/github/api.ts b/extensions/github-browser/src/github/api.ts deleted file mode 100644 index bb2bb65cb6d..00000000000 --- a/extensions/github-browser/src/github/api.ts +++ /dev/null @@ -1,504 +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 { authentication, AuthenticationSession, Disposable, Event, EventEmitter, Range, Uri } from 'vscode'; -import { graphql } from '@octokit/graphql'; -import { Octokit } from '@octokit/rest'; -import { ContextStore } from '../contextStore'; -import { fromGitHubUri } from './fs'; -import { isSha } from '../extension'; -import { Iterables } from '../iterables'; - -export interface GitHubApiContext { - requestRef: string; - - branch: string; - sha: string | undefined; - timestamp: number; -} - -interface CreateCommitOperation { - type: 'created'; - path: string; - content: string -} - -interface ChangeCommitOperation { - type: 'changed'; - path: string; - content: string -} - -interface DeleteCommitOperation { - type: 'deleted'; - path: string; - content: undefined -} - -export type CommitOperation = CreateCommitOperation | ChangeCommitOperation | DeleteCommitOperation; - -type ArrayElement> = T extends (infer U)[] ? U : never; -type GitCreateTreeParamsTree = ArrayElement[0]>['tree']>; - -function getGitHubRootUri(uri: Uri) { - const rootIndex = uri.path.indexOf('/', uri.path.indexOf('/', 1) + 1); - return uri.with({ - path: uri.path.substring(0, rootIndex === -1 ? undefined : rootIndex), - query: '' - }); -} - -export class GitHubApi implements Disposable { - private _onDidChangeContext = new EventEmitter(); - get onDidChangeContext(): Event { - return this._onDidChangeContext.event; - } - - private readonly disposable: Disposable; - - constructor(private readonly context: ContextStore) { - this.disposable = Disposable.from( - context.onDidChange(e => this._onDidChangeContext.fire(e)) - ); - } - - dispose() { - this.disposable.dispose(); - } - - private _session: AuthenticationSession | undefined; - async ensureAuthenticated() { - if (this._session === undefined) { - const providers = await authentication.getProviderIds(); - if (!providers.includes('github')) { - await new Promise(resolve => { - authentication.onDidChangeAuthenticationProviders(e => { - if (e.added.find(provider => provider.id === 'github')) { - resolve(); - } - }); - }); - } - - this._session = await authentication.getSession('github', ['repo'], { createIfNone: true }); - } - - return this._session; - } - - private _graphql: typeof graphql | undefined; - private async graphql() { - if (this._graphql === undefined) { - const session = await this.ensureAuthenticated(); - this._graphql = graphql.defaults({ - headers: { - Authorization: `Bearer ${session.accessToken}`, - } - }); - } - - return this._graphql; - } - - private _octokit: typeof Octokit | undefined; - private async octokit(options?: ConstructorParameters[0]) { - if (this._octokit === undefined) { - const session = await this.ensureAuthenticated(); - this._octokit = Octokit.defaults({ auth: `token ${session.accessToken}` }); - } - return new this._octokit(options); - } - - async commit(rootUri: Uri, message: string, operations: CommitOperation[]): Promise { - const { owner, repo } = fromGitHubUri(rootUri); - - try { - const context = await this.getContext(rootUri); - if (context.sha === undefined) { - throw new Error(`Cannot commit to Uri(${rootUri.toString(true)}); Invalid context sha`); - } - - const hasDeletes = operations.some(op => op.type === 'deleted'); - - const github = await this.octokit(); - const treeResp = await github.git.getTree({ - owner: owner, - repo: repo, - tree_sha: context.sha, - recursive: hasDeletes ? 'true' : undefined, - }); - - // 0100000000000000 (040000): Directory - // 1000000110100100 (100644): Regular non-executable file - // 1000000110110100 (100664): Regular non-executable group-writeable file - // 1000000111101101 (100755): Regular executable file - // 1010000000000000 (120000): Symbolic link - // 1110000000000000 (160000): Gitlink - let updatedTree: GitCreateTreeParamsTree[]; - - if (hasDeletes) { - updatedTree = treeResp.data.tree as GitCreateTreeParamsTree[]; - - for (const operation of operations) { - switch (operation.type) { - case 'created': - updatedTree.push({ path: operation.path, mode: '100644', type: 'blob', content: operation.content }); - break; - - case 'changed': { - const index = updatedTree.findIndex(item => item.path === operation.path); - if (index !== -1) { - const { path, mode, type } = updatedTree[index]; - updatedTree.splice(index, 1, { path: path, mode: mode, type: type, content: operation.content }); - } - break; - } - case 'deleted': { - const index = updatedTree.findIndex(item => item.path === operation.path); - if (index !== -1) { - updatedTree.splice(index, 1); - } - break; - } - } - } - } else { - updatedTree = []; - - for (const operation of operations) { - switch (operation.type) { - case 'created': - updatedTree.push({ path: operation.path, mode: '100644', type: 'blob', content: operation.content }); - break; - - case 'changed': - const item = treeResp.data.tree.find(item => item.path === operation.path) as GitCreateTreeParamsTree; - if (item !== undefined) { - const { path, mode, type } = item; - updatedTree.push({ path: path, mode: mode, type: type, content: operation.content }); - } - break; - } - } - } - - const updatedTreeResp = await github.git.createTree({ - owner: owner, - repo: repo, - base_tree: hasDeletes ? undefined : treeResp.data.sha, - tree: updatedTree - }); - - const resp = await github.git.createCommit({ - owner: owner, - repo: repo, - message: message, - tree: updatedTreeResp.data.sha, - parents: [context.sha] - }); - - this.updateContext(rootUri, { ...context, sha: resp.data.sha, timestamp: Date.now() }); - - // TODO@eamodio need to send a file change for any open files - - await github.git.updateRef({ - owner: owner, - repo: repo, - ref: `heads/${context.branch}`, - sha: resp.data.sha - }); - - return resp.data.sha; - } catch (ex) { - console.log(ex); - throw ex; - } - } - - async defaultBranchQuery(uri: Uri) { - const { owner, repo } = fromGitHubUri(uri); - - try { - const query = `query defaultBranch($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - defaultBranchRef { - name - } - } -}`; - - const rsp = await this.gqlQuery<{ - repository: { defaultBranchRef: { name: string; target: { oid: string } } | null | undefined }; - }>(query, { - owner: owner, - repo: repo, - }); - return rsp?.repository?.defaultBranchRef?.name ?? undefined; - } catch (ex) { - return undefined; - } - } - - async filesQuery(uri: Uri) { - const { owner, repo, ref } = fromGitHubUri(uri); - - try { - const context = await this.getContext(uri); - - const resp = await (await this.octokit()).git.getTree({ - owner: owner, - repo: repo, - recursive: '1', - tree_sha: context?.sha ?? ref, - }); - return Iterables.filterMap(resp.data.tree, p => p.type === 'blob' ? p.path : undefined); - } catch (ex) { - return []; - } - } - - async fsQuery(uri: Uri, innerQuery: string): Promise { - const { owner, repo, path, ref } = fromGitHubUri(uri); - - try { - const context = await this.getContext(uri); - - const query = `query fs($owner: String!, $repo: String!, $path: String) { - repository(owner: $owner, name: $repo) { - object(expression: $path) { - ${innerQuery} - } - } -}`; - - const rsp = await this.gqlQuery<{ - repository: { object: T | null | undefined }; - }>(query, { - owner: owner, - repo: repo, - path: `${context.sha ?? ref}:${path}`, - }); - return rsp?.repository?.object ?? undefined; - } catch (ex) { - return undefined; - } - } - - async latestCommitQuery(uri: Uri) { - const { owner, repo, ref } = fromGitHubUri(uri); - - try { - if (ref === 'HEAD') { - const query = `query latest($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - defaultBranchRef { - target { - oid - } - } - } -}`; - - const rsp = await this.gqlQuery<{ - repository: { defaultBranchRef: { name: string; target: { oid: string } } | null | undefined }; - }>(query, { - owner: owner, - repo: repo, - }); - return rsp?.repository?.defaultBranchRef?.target.oid ?? undefined; - } - - const query = `query latest($owner: String!, $repo: String!, $ref: String!) { - repository(owner: $owner, name: $repo) { - ref(qualifiedName: $ref) { - target { - oid - } - } - } -}`; - - const rsp = await this.gqlQuery<{ - repository: { ref: { target: { oid: string } } | null | undefined }; - }>(query, { - owner: owner, - repo: repo, - ref: ref ?? 'HEAD', - }); - return rsp?.repository?.ref?.target.oid ?? undefined; - } catch (ex) { - return undefined; - } - } - - async searchQuery( - query: string, - uri: Uri, - options: { maxResults?: number; context?: { before?: number; after?: number } }, - ): Promise { - const { owner, repo, ref } = fromGitHubUri(uri); - - // If we have a specific ref, don't try to search, because GitHub search only works against the default branch - if (ref !== 'HEAD') { - return { matches: [], limitHit: true }; - } - - try { - const resp = await (await this.octokit({ - request: { - headers: { - accept: 'application/vnd.github.v3.text-match+json', - }, - } - })).search.code({ - q: `${query} repo:${owner}/${repo}`, - }); - - // Since GitHub doesn't return ANY line numbers just fake it at the top of the file 😢 - const range = new Range(0, 0, 0, 0); - - const matches: SearchQueryMatch[] = []; - - let counter = 0; - let match: SearchQueryMatch; - for (const item of resp.data.items) { - for (const m of (item as typeof item & { text_matches: GitHubSearchTextMatch[] }).text_matches) { - counter++; - if (options.maxResults !== undefined && counter > options.maxResults) { - return { matches: matches, limitHit: true }; - } - - match = { - path: item.path, - ranges: [], - preview: m.fragment, - matches: [], - }; - - for (const lm of m.matches) { - let line = 0; - let shartChar = 0; - let endChar = 0; - for (let i = 0; i < lm.indices[1]; i++) { - if (i === lm.indices[0]) { - shartChar = endChar; - } - - if (m.fragment[i] === '\n') { - line++; - endChar = 0; - } else { - endChar++; - } - } - - match.ranges.push(range); - match.matches.push(new Range(line, shartChar, line, endChar)); - } - - matches.push(match); - } - } - - return { matches: matches, limitHit: false }; - } catch (ex) { - return { matches: [], limitHit: true }; - } - } - - private async gqlQuery(query: string, variables: { [key: string]: string | number }): Promise { - return (await this.graphql())(query, variables); - } - - private readonly pendingContextRequests = new Map>(); - async getContext(uri: Uri): Promise { - const rootUri = getGitHubRootUri(uri); - - let pending = this.pendingContextRequests.get(rootUri.toString()); - if (pending === undefined) { - pending = this.getContextCore(rootUri); - this.pendingContextRequests.set(rootUri.toString(), pending); - } - - try { - return await pending; - } finally { - this.pendingContextRequests.delete(rootUri.toString()); - } - } - - private readonly rootUriToContextMap = new Map(); - - private async getContextCore(rootUri: Uri): Promise { - const key = rootUri.toString(); - let context = this.rootUriToContextMap.get(key); - - // Check if we have a cached a context - if (context?.sha !== undefined) { - return context; - } - - // Check if we have a saved context - context = this.context.get(rootUri); - if (context?.sha !== undefined) { - this.rootUriToContextMap.set(key, context); - - return context; - } - - const { ref } = fromGitHubUri(rootUri); - - // If the requested ref looks like a sha, then use it - if (isSha(ref)) { - context = { requestRef: ref, branch: ref, sha: ref, timestamp: Date.now() }; - } else { - let branch; - if (ref === 'HEAD') { - branch = await this.defaultBranchQuery(rootUri); - if (branch === undefined) { - throw new Error(`Cannot get context for Uri(${rootUri.toString(true)}); unable to get default branch`); - } - } else { - branch = ref; - } - - // Query for the latest sha for the give ref - const sha = await this.latestCommitQuery(rootUri); - context = { requestRef: ref, branch: branch, sha: sha, timestamp: Date.now() }; - } - - this.updateContext(rootUri, context); - - return context; - } - - private updateContext(rootUri: Uri, context: GitHubApiContext) { - this.rootUriToContextMap.set(rootUri.toString(), context); - this.context.set(rootUri, context); - } -} - -interface GitHubSearchTextMatch { - object_url: string; - object_type: string; - property: string; - fragment: string; - matches: { - text: string; - indices: number[]; - }[]; -} - -interface SearchQueryMatch { - path: string; - ranges: Range[]; - preview: string; - matches: Range[]; -} - -interface SearchQueryResults { - matches: SearchQueryMatch[]; - limitHit: boolean; -} diff --git a/extensions/github-browser/src/github/fs.ts b/extensions/github-browser/src/github/fs.ts deleted file mode 100644 index d0af10751c0..00000000000 --- a/extensions/github-browser/src/github/fs.ts +++ /dev/null @@ -1,332 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { - CancellationToken, - Disposable, - Event, - EventEmitter, - FileChangeEvent, - FileSearchOptions, - FileSearchProvider, - FileSearchQuery, - FileStat, - FileSystemError, - FileSystemProvider, - FileType, - Progress, - TextSearchComplete, - TextSearchOptions, - TextSearchProvider, - TextSearchQuery, - TextSearchResult, - Uri, - workspace, -} from 'vscode'; -import * as fuzzySort from 'fuzzysort'; -import fetch from 'node-fetch'; -import { GitHubApi } from './api'; -import { Iterables } from '../iterables'; -import { getRootUri } from '../extension'; - -const emptyDisposable = { dispose: () => { /* noop */ } }; -const replaceBackslashRegex = /(\/|\\)/g; -const textEncoder = new TextEncoder(); - -interface Fuzzysort extends Fuzzysort.Fuzzysort { - prepareSlow(target: string): Fuzzysort.Prepared; - cleanup(): void; -} - -export class GitHubFS implements FileSystemProvider, FileSearchProvider, TextSearchProvider, Disposable { - static scheme = 'github'; - - private _onDidChangeFile = new EventEmitter(); - get onDidChangeFile(): Event { - return this._onDidChangeFile.event; - } - - private readonly disposable: Disposable; - private fsCache = new Map>(); - - constructor(private readonly github: GitHubApi) { - this.disposable = Disposable.from( - workspace.registerFileSystemProvider(GitHubFS.scheme, this, { - isCaseSensitive: true, - isReadonly: true - }), - workspace.registerFileSearchProvider(GitHubFS.scheme, this), - workspace.registerTextSearchProvider(GitHubFS.scheme, this), - github.onDidChangeContext(e => this.fsCache.delete(e.toString())) - ); - } - - dispose() { - this.disposable?.dispose(); - } - - private getCache(uri: Uri) { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return undefined; - } - - let cache = this.fsCache.get(rootUri.toString()); - if (cache === undefined) { - cache = new Map(); - this.fsCache.set(rootUri.toString(), cache); - } - return cache; - } - - //#region FileSystemProvider - - watch(): Disposable { - return emptyDisposable; - } - - async stat(uri: Uri): Promise { - if (uri.path === '' || uri.path.lastIndexOf('/') === 0) { - const context = await this.github.getContext(uri); - return { type: FileType.Directory, size: 0, ctime: 0, mtime: context?.timestamp }; - } - - const data = await this.fsQuery<{ - __typename: string; - byteSize: number | undefined; - }>( - uri, - `__typename - ...on Blob { - byteSize - }`, - this.getCache(uri), - ); - - if (data === undefined) { - throw FileSystemError.FileNotFound(); - } - - const context = await this.github.getContext(uri); - - return { - type: typenameToFileType(data.__typename), - size: data.byteSize ?? 0, - ctime: 0, - mtime: context?.timestamp, - }; - } - - async readDirectory(uri: Uri): Promise<[string, FileType][]> { - const data = await this.fsQuery<{ - entries: { name: string; type: string }[]; - }>( - uri, - `... on Tree { - entries { - name - type - } - }`, - this.getCache(uri), - ); - - return (data?.entries ?? []).map<[string, FileType]>(e => [ - e.name, - typenameToFileType(e.type), - ]); - } - - createDirectory(_uri: Uri): void | Thenable { - throw FileSystemError.NoPermissions(); - } - - async readFile(uri: Uri): Promise { - const data = await this.fsQuery<{ - oid: string; - isBinary: boolean; - text: string; - }>( - uri, - `... on Blob { - oid, - isBinary, - text - }`, - ); - - if (data?.isBinary) { - const { owner, repo, path } = fromGitHubUri(uri); - // e.g. https://raw.githubusercontent.com/eamodio/vscode-gitlens/HEAD/images/gitlens-icon.png - const downloadUri = uri.with({ - scheme: 'https', - authority: 'raw.githubusercontent.com', - path: `/${owner}/${repo}/HEAD/${path}`, - }); - - return downloadBinary(downloadUri); - } - - return textEncoder.encode(data?.text ?? ''); - } - - async writeFile(_uri: Uri, _content: Uint8Array, _options: { create: boolean, overwrite: boolean }): Promise { - throw FileSystemError.NoPermissions(); - } - - delete(_uri: Uri, _options: { recursive: boolean }): void | Thenable { - throw FileSystemError.NoPermissions(); - } - - rename(_oldUri: Uri, _newUri: Uri, _options: { overwrite: boolean }): void | Thenable { - throw FileSystemError.NoPermissions(); - } - - copy(_source: Uri, _destination: Uri, _options: { overwrite: boolean }): void | Thenable { - throw FileSystemError.NoPermissions(); - } - - //#endregion - - //#region FileSearchProvider - - private fileSearchCache = new Map(); - - async provideFileSearchResults( - query: FileSearchQuery, - options: FileSearchOptions, - token: CancellationToken, - ): Promise { - let searchable = this.fileSearchCache.get(options.folder.toString(true)); - if (searchable === undefined) { - const matches = await this.github.filesQuery(options.folder); - if (matches === undefined || token.isCancellationRequested) { - return []; - } - - searchable = [...Iterables.map(matches, m => (fuzzySort as Fuzzysort).prepareSlow(m))]; - this.fileSearchCache.set(options.folder.toString(true), searchable); - } - - if (options.maxResults === undefined || options.maxResults === 0 || options.maxResults >= searchable.length) { - const results = searchable.map(m => Uri.joinPath(options.folder, m.target)); - return results; - } - - const results = fuzzySort - .go(query.pattern.replace(replaceBackslashRegex, '/'), searchable, { - allowTypo: true, - limit: options.maxResults, - }) - .map(m => Uri.joinPath(options.folder, m.target)); - - (fuzzySort as Fuzzysort).cleanup(); - - return results; - } - - //#endregion - - //#region TextSearchProvider - - async provideTextSearchResults( - query: TextSearchQuery, - options: TextSearchOptions, - progress: Progress, - _token: CancellationToken, - ): Promise { - const results = await this.github.searchQuery( - query.pattern, - options.folder, - { maxResults: options.maxResults, context: { before: options.beforeContext, after: options.afterContext } }, - ); - if (results === undefined) { return { limitHit: true }; } - - let uri; - for (const m of results.matches) { - uri = Uri.joinPath(options.folder, m.path); - - progress.report({ - uri: uri, - ranges: m.ranges, - preview: { - text: m.preview, - matches: m.matches, - }, - }); - } - - return { limitHit: false }; - } - - //#endregion - - private async fsQuery(uri: Uri, query: string, cache?: Map): Promise { - const key = `${uri.toString()}:${getHashCode(query)}`; - - let data = cache?.get(key); - if (data !== undefined) { - return data as T; - } - - data = await this.github.fsQuery(uri, query); - cache?.set(key, data); - return data; - } -} - -async function downloadBinary(uri: Uri) { - const resp = await fetch(uri.toString()); - const array = new Uint8Array(await resp.arrayBuffer()); - return array; -} - -function typenameToFileType(typename: string | undefined | null) { - if (typename) { - typename = typename.toLocaleLowerCase(); - } - - switch (typename) { - case 'blob': - return FileType.File; - case 'tree': - return FileType.Directory; - default: - return FileType.Unknown; - } -} - -type RepoInfo = { owner: string; repo: string; path: string | undefined; ref: string }; -export function fromGitHubUri(uri: Uri): RepoInfo { - const [, owner, repo, ...rest] = uri.path.split('/'); - - let ref; - if (uri.authority) { - ref = uri.authority; - // The casing of HEAD is important for the GitHub api to work - if (/HEAD/i.test(ref)) { - ref = 'HEAD'; - } - } - return { owner: owner, repo: repo, path: rest.join('/'), ref: ref ?? 'HEAD' }; -} - -function getHashCode(s: string): number { - let hash = 0; - - if (s.length === 0) { - return hash; - } - - let char; - const len = s.length; - for (let i = 0; i < len; i++) { - char = s.charCodeAt(i); - hash = ((hash << 5) - hash) + char; - hash |= 0; // Convert to 32bit integer - } - return hash; -} diff --git a/extensions/github-browser/src/iterables.ts b/extensions/github-browser/src/iterables.ts deleted file mode 100644 index 5679e2c81ec..00000000000 --- a/extensions/github-browser/src/iterables.ts +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -export namespace Iterables { - export function* filterMap( - source: Iterable | IterableIterator, - predicateMapper: (item: T) => TMapped | undefined | null, - ): Iterable { - for (const item of source) { - const mapped = predicateMapper(item); - if (mapped !== undefined && mapped !== null) { - yield mapped; - } - } - } - - export function* map( - source: Iterable | IterableIterator, - mapper: (item: T) => TMapped, - ): Iterable { - for (const item of source) { - yield mapper(item); - } - } -} diff --git a/extensions/github-browser/src/scm.ts b/extensions/github-browser/src/scm.ts deleted file mode 100644 index 7a8e4292f22..00000000000 --- a/extensions/github-browser/src/scm.ts +++ /dev/null @@ -1,177 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { CancellationToken, commands, Disposable, scm, SourceControl, SourceControlResourceGroup, SourceControlResourceState, Uri, window, workspace } from 'vscode'; -import * as nls from 'vscode-nls'; -import { IChangeStore } from './changeStore'; -import { GitHubApi, CommitOperation } from './github/api'; -import { getRelativePath } from './extension'; - -const localize = nls.loadMessageBundle(); - -interface ScmProvider { - sourceControl: SourceControl, - groups: SourceControlResourceGroup[] -} - -export class VirtualSCM implements Disposable { - private readonly providers: ScmProvider[] = []; - - private disposable: Disposable; - - constructor( - private readonly originalScheme: string, - private readonly github: GitHubApi, - private readonly changeStore: IChangeStore, - ) { - this.registerCommands(); - - // TODO@eamodio listen for workspace folder changes - for (const folder of workspace.workspaceFolders ?? []) { - this.createScmProvider(folder.uri, folder.name); - - for (const operation of changeStore.getChanges(folder.uri)) { - this.update(folder.uri, operation.uri); - } - } - - this.disposable = Disposable.from( - changeStore.onDidChange(e => this.update(e.rootUri, e.uri)), - ); - } - - dispose() { - this.disposable.dispose(); - } - - private registerCommands() { - commands.registerCommand('githubBrowser.commit', (sourceControl: SourceControl | undefined) => { - // TODO@eamodio remove this hack once I figure out why the args are missing - if (sourceControl === undefined && this.providers.length === 1) { - sourceControl = this.providers[0].sourceControl; - } - - if (sourceControl === undefined) { - return; - } - - this.commitChanges(sourceControl); - }); - - commands.registerCommand('githubBrowser.discardChanges', (resourceState: SourceControlResourceState) => - this.discardChanges(resourceState.resourceUri) - ); - - commands.registerCommand('githubBrowser.openChanges', (resourceState: SourceControlResourceState) => - this.openChanges(resourceState.resourceUri) - ); - - commands.registerCommand('githubBrowser.openFile', (resourceState: SourceControlResourceState) => - this.openFile(resourceState.resourceUri) - ); - } - - async commitChanges(sourceControl: SourceControl): Promise { - const operations = this.changeStore - .getChanges(sourceControl.rootUri!) - .map(operation => { - const path = getRelativePath(sourceControl.rootUri!, operation.uri); - switch (operation.type) { - case 'created': - return { type: operation.type, path: path, content: this.changeStore.getContent(operation.uri)! }; - case 'changed': - return { type: operation.type, path: path, content: this.changeStore.getContent(operation.uri)! }; - case 'deleted': - return { type: operation.type, path: path }; - } - }); - if (!operations.length) { - window.showInformationMessage(localize('no changes', "There are no changes to commit.")); - - return; - } - - const message = sourceControl.inputBox.value; - if (message) { - const sha = await this.github.commit(this.getOriginalResource(sourceControl.rootUri!), message, operations); - if (sha !== undefined) { - this.changeStore.acceptAll(sourceControl.rootUri!); - sourceControl.inputBox.value = ''; - } - } - } - - discardChanges(uri: Uri): Promise { - return this.changeStore.discard(uri); - } - - openChanges(uri: Uri) { - return this.changeStore.openChanges(uri, this.getOriginalResource(uri)); - } - - openFile(uri: Uri) { - return this.changeStore.openFile(uri); - } - - private update(rootUri: Uri, uri: Uri) { - const folder = workspace.getWorkspaceFolder(uri); - if (folder === undefined) { - return; - } - - const provider = this.createScmProvider(rootUri, folder.name); - const group = this.createChangesGroup(provider); - group.resourceStates = this.changeStore.getChanges(rootUri).map(op => { - const rs: SourceControlResourceState = { - decorations: { - strikeThrough: op.type === 'deleted' - }, - resourceUri: op.uri, - command: { - command: 'githubBrowser.openChanges', - title: 'Open Changes', - } - }; - rs.command!.arguments = [rs]; - return rs; - }); - } - - private createScmProvider(rootUri: Uri, name: string) { - let provider = this.providers.find(sc => sc.sourceControl.rootUri?.toString() === rootUri.toString()); - if (provider === undefined) { - const sourceControl = scm.createSourceControl('github', name, rootUri); - sourceControl.quickDiffProvider = { provideOriginalResource: uri => this.getOriginalResource(uri) }; - sourceControl.acceptInputCommand = { - command: 'githubBrowser.commit', - title: 'Commit', - arguments: [sourceControl] - }; - sourceControl.inputBox.placeholder = `Message (Ctrl+Enter to commit '${name}')`; - // sourceControl.inputBox.validateInput = value => value ? undefined : 'Invalid commit message'; - - provider = { sourceControl: sourceControl, groups: [] }; - this.createChangesGroup(provider); - this.providers.push(provider); - } - - return provider; - } - - private createChangesGroup(provider: ScmProvider) { - let group = provider.groups.find(g => g.id === 'github.changes'); - if (group === undefined) { - group = provider.sourceControl.createResourceGroup('github.changes', 'Changes'); - provider.groups.push(group); - } - - return group; - } - - private getOriginalResource(uri: Uri, _token?: CancellationToken): Uri { - return uri.with({ scheme: this.originalScheme }); - } -} diff --git a/extensions/github-browser/src/sha1.ts b/extensions/github-browser/src/sha1.ts deleted file mode 100644 index 0469b3c98a1..00000000000 --- a/extensions/github-browser/src/sha1.ts +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -const textDecoder = new TextDecoder(); -const textEncoder = new TextEncoder(); - -declare let WEBWORKER: boolean; - -export async function sha1(s: string | Uint8Array): Promise { - while (true) { - try { - if (WEBWORKER) { - const hash = await globalThis.crypto.subtle.digest({ name: 'sha-1' }, typeof s === 'string' ? textEncoder.encode(s) : s); - // Use encodeURIComponent to avoid issues with btoa and Latin-1 characters - return globalThis.btoa(encodeURIComponent(textDecoder.decode(hash))); - } else { - return (await import('crypto')).createHash('sha1').update(s).digest('base64'); - } - } catch (ex) { - if (ex instanceof ReferenceError) { - (global as any).WEBWORKER = false; - } - } - } -} diff --git a/extensions/github-browser/src/statusbar.ts b/extensions/github-browser/src/statusbar.ts deleted file mode 100644 index e5a049a8631..00000000000 --- a/extensions/github-browser/src/statusbar.ts +++ /dev/null @@ -1,99 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { Disposable, StatusBarAlignment, StatusBarItem, Uri, window, workspace } from 'vscode'; -import { ChangeStoreEvent, IChangeStore } from './changeStore'; -import { GitHubApiContext } from './github/api'; -import { isSha } from './extension'; -import { ContextStore, WorkspaceFolderContext } from './contextStore'; - -export class StatusBar implements Disposable { - private readonly disposable: Disposable; - - private readonly items = new Map(); - - constructor( - private readonly contextStore: ContextStore, - private readonly changeStore: IChangeStore - ) { - this.disposable = Disposable.from( - contextStore.onDidChange(this.onContextsChanged, this), - changeStore.onDidChange(this.onChanged, this) - ); - - for (const context of this.contextStore.getForWorkspace()) { - this.createOrUpdateStatusBarItem(context); - } - } - - dispose() { - this.disposable?.dispose(); - this.items.forEach(i => i.dispose()); - } - - private createOrUpdateStatusBarItem(wc: WorkspaceFolderContext) { - let item = this.items.get(wc.folderUri.toString()); - if (item === undefined) { - item = window.createStatusBarItem({ - id: `githubBrowser.branch:${wc.folderUri.toString()}`, - name: `GitHub Browser: ${wc.name}`, - alignment: StatusBarAlignment.Left, - priority: 1000 - }); - } - - if (isSha(wc.context.branch)) { - item.text = `$(git-commit) ${wc.context.branch.substr(0, 8)}`; - item.tooltip = `${wc.name} \u2022 ${wc.context.branch.substr(0, 8)}`; - } else { - item.text = `$(git-branch) ${wc.context.branch}`; - item.tooltip = `${wc.name} \u2022 ${wc.context.branch}${wc.context.sha ? ` @ ${wc.context.sha?.substr(0, 8)}` : ''}`; - } - - const hasChanges = this.changeStore.hasChanges(wc.folderUri); - if (hasChanges) { - item.text += '*'; - } - - item.show(); - - this.items.set(wc.folderUri.toString(), item); - } - - private onContextsChanged(uri: Uri) { - const folder = workspace.getWorkspaceFolder(this.contextStore.getWorkspaceResource(uri)); - if (folder === undefined) { - return; - } - - const context = this.contextStore.get(uri); - if (context === undefined) { - return; - } - - this.createOrUpdateStatusBarItem({ - context: context, - name: folder.name, - folderUri: folder.uri, - }); - } - - private onChanged(e: ChangeStoreEvent) { - const item = this.items.get(e.rootUri.toString()); - if (item !== undefined) { - const hasChanges = this.changeStore.hasChanges(e.rootUri); - if (hasChanges) { - if (!item.text.endsWith('*')) { - item.text += '*'; - } - } else { - if (item.text.endsWith('*')) { - item.text = item.text.substr(0, item.text.length - 1); - } - } - } - } -} diff --git a/extensions/github-browser/src/typings/ref.d.ts b/extensions/github-browser/src/typings/ref.d.ts deleted file mode 100644 index 312efe5a30f..00000000000 --- a/extensions/github-browser/src/typings/ref.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/// -/// -/// diff --git a/extensions/github-browser/yarn.lock b/extensions/github-browser/yarn.lock deleted file mode 100644 index 2c8f1ad9658..00000000000 --- a/extensions/github-browser/yarn.lock +++ /dev/null @@ -1,332 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@octokit/auth-token@^2.4.0": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.2.tgz#10d0ae979b100fa6b72fa0e8e63e27e6d0dbff8a" - integrity sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ== - dependencies: - "@octokit/types" "^5.0.0" - -"@octokit/core@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.1.0.tgz#9c3c9b23f7504668cfa057f143ccbf0c645a0ac9" - integrity sha512-yPyQSmxIXLieEIRikk2w8AEtWkFdfG/LXcw1KvEtK3iP0ENZLW/WYQmdzOKqfSaLhooz4CJ9D+WY79C8ZliACw== - dependencies: - "@octokit/auth-token" "^2.4.0" - "@octokit/graphql" "^4.3.1" - "@octokit/request" "^5.4.0" - "@octokit/types" "^5.0.0" - before-after-hook "^2.1.0" - universal-user-agent "^5.0.0" - -"@octokit/endpoint@^6.0.1": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.3.tgz#dd09b599662d7e1b66374a177ab620d8cdf73487" - integrity sha512-Y900+r0gIz+cWp6ytnkibbD95ucEzDSKzlEnaWS52hbCDNcCJYO5mRmWW7HRAnDc7am+N/5Lnd8MppSaTYx1Yg== - dependencies: - "@octokit/types" "^5.0.0" - is-plain-object "^3.0.0" - universal-user-agent "^5.0.0" - -"@octokit/graphql@4.5.1", "@octokit/graphql@^4.3.1": - version "4.5.1" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.5.1.tgz#162aed1490320b88ce34775b3f6b8de945529fa9" - integrity sha512-qgMsROG9K2KxDs12CO3bySJaYoUu2aic90qpFrv7A8sEBzZ7UFGvdgPKiLw5gOPYEYbS0Xf8Tvf84tJutHPulQ== - dependencies: - "@octokit/request" "^5.3.0" - "@octokit/types" "^5.0.0" - universal-user-agent "^5.0.0" - -"@octokit/plugin-paginate-rest@^2.2.0": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.2.3.tgz#a6ad4377e7e7832fb4bdd9d421e600cb7640ac27" - integrity sha512-eKTs91wXnJH8Yicwa30jz6DF50kAh7vkcqCQ9D7/tvBAP5KKkg6I2nNof8Mp/65G0Arjsb4QcOJcIEQY+rK1Rg== - dependencies: - "@octokit/types" "^5.0.0" - -"@octokit/plugin-request-log@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e" - integrity sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw== - -"@octokit/plugin-rest-endpoint-methods@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.0.0.tgz#b02a2006dda8e908c3f8ab381dd5475ef5a810a8" - integrity sha512-emS6gysz4E9BNi9IrCl7Pm4kR+Az3MmVB0/DoDCmF4U48NbYG3weKyDlgkrz6Jbl4Mu4nDx8YWZwC4HjoTdcCA== - dependencies: - "@octokit/types" "^5.0.0" - deprecation "^2.3.1" - -"@octokit/request-error@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.2.tgz#0e76b83f5d8fdda1db99027ea5f617c2e6ba9ed0" - integrity sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw== - dependencies: - "@octokit/types" "^5.0.1" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request@^5.3.0", "@octokit/request@^5.4.0": - version "5.4.5" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.5.tgz#8df65bd812047521f7e9db6ff118c06ba84ac10b" - integrity sha512-atAs5GAGbZedvJXXdjtKljin+e2SltEs48B3naJjqWupYl2IUBbB/CJisyjbNHcKpHzb3E+OYEZ46G8eakXgQg== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.0.0" - "@octokit/types" "^5.0.0" - deprecation "^2.0.0" - is-plain-object "^3.0.0" - node-fetch "^2.3.0" - once "^1.4.0" - universal-user-agent "^5.0.0" - -"@octokit/rest@18.0.0": - version "18.0.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.0.0.tgz#7f401d9ce13530ad743dfd519ae62ce49bcc0358" - integrity sha512-4G/a42lry9NFGuuECnua1R1eoKkdBYJap97jYbWDNYBOUboWcM75GJ1VIcfvwDV/pW0lMPs7CEmhHoVrSV5shg== - dependencies: - "@octokit/core" "^3.0.0" - "@octokit/plugin-paginate-rest" "^2.2.0" - "@octokit/plugin-request-log" "^1.0.0" - "@octokit/plugin-rest-endpoint-methods" "4.0.0" - -"@octokit/types@^5.0.0", "@octokit/types@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-5.0.1.tgz#5459e9a5e9df8565dcc62c17a34491904d71971e" - integrity sha512-GorvORVwp244fGKEt3cgt/P+M0MGy4xEDbckw+K5ojEezxyMDgCaYPKVct+/eWQfZXOT7uq0xRpmrl/+hliabA== - dependencies: - "@types/node" ">= 8" - -"@types/node-fetch@2.5.7": - version "2.5.7" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" - integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - -"@types/node@*", "@types/node@>= 8": - version "14.0.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.14.tgz#24a0b5959f16ac141aeb0c5b3cd7a15b7c64cbce" - integrity sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -before-after-hook@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" - integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -fuzzysort@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-1.1.4.tgz#a0510206ed44532cbb52cf797bf5a3cb12acd4ba" - integrity sha512-JzK/lHjVZ6joAg3OnCjylwYXYVjRiwTY6Yb25LvfpJHK8bjisfnZJ5bY8aVWwTwCXgxPNgLAtmHL+Hs5q1ddLQ== - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -is-plain-object@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b" - integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g== - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -macos-release@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f" - integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA== - -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-types@^2.1.12: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== - dependencies: - mime-db "1.44.0" - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-fetch@2.6.0, node-fetch@^2.3.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -os-name@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" - integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== - dependencies: - macos-release "^2.2.0" - windows-release "^3.1.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -semver@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -signal-exit@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -universal-user-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-5.0.0.tgz#a3182aa758069bf0e79952570ca757de3579c1d9" - integrity sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q== - dependencies: - os-name "^3.1.0" - -vscode-nls@4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167" - integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw== - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -windows-release@^3.1.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.1.tgz#cb4e80385f8550f709727287bf71035e209c4ace" - integrity sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A== - dependencies: - execa "^1.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= diff --git a/extensions/github/src/publish.ts b/extensions/github/src/publish.ts index 0e8dc89b3ad..9cd79a749b7 100644 --- a/extensions/github/src/publish.ts +++ b/extensions/github/src/publish.ts @@ -140,9 +140,11 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository) const ignored = new Set(children); result.forEach(c => ignored.delete(c.label)); - const raw = [...ignored].map(i => `/${i}`).join('\n'); - const encoder = new TextEncoder(); - await vscode.workspace.fs.writeFile(gitignore, encoder.encode(raw)); + if (ignored.size > 0) { + const raw = [...ignored].map(i => `/${i}`).join('\n'); + const encoder = new TextEncoder(); + await vscode.workspace.fs.writeFile(gitignore, encoder.encode(raw)); + } } finally { quickpick.dispose(); } diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index 534756ac81d..0d70cdd4828 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -148,9 +148,12 @@ class FolderDetector { } let gulpfile = path.join(rootPath, 'gulpfile.js'); if (!await exists(gulpfile)) { - gulpfile = path.join(rootPath, 'gulpfile.babel.js'); - if (! await exists(gulpfile)) { - return emptyTasks; + gulpfile = path.join(rootPath, 'Gulpfile.js'); + if (!await exists(gulpfile)) { + gulpfile = path.join(rootPath, 'gulpfile.babel.js'); + if (!await exists(gulpfile)) { + return emptyTasks; + } } } diff --git a/extensions/html-language-features/.vscodeignore b/extensions/html-language-features/.vscodeignore index 4215adf6eca..a4a4702c351 100644 --- a/extensions/html-language-features/.vscodeignore +++ b/extensions/html-language-features/.vscodeignore @@ -16,5 +16,7 @@ server/.npmignore yarn.lock server/extension.webpack.config.js extension.webpack.config.js +server/extension-browser.webpack.config.js +extension-browser.webpack.config.js CONTRIBUTING.md cgmanifest.json diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index d7e2a8b28fb..eadd61b33d0 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,7 +9,7 @@ }, "main": "./out/node/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^4.3.0", + "vscode-css-languageservice": "^4.3.1", "vscode-html-languageservice": "^3.1.0", "vscode-languageserver": "7.0.0-next.3", "vscode-nls": "^4.1.2", diff --git a/extensions/html-language-features/server/src/test/folding.test.ts b/extensions/html-language-features/server/src/test/folding.test.ts index 272a81463fd..693a74420f0 100644 --- a/extensions/html-language-features/server/src/test/folding.test.ts +++ b/extensions/html-language-features/server/src/test/folding.test.ts @@ -71,7 +71,7 @@ suite('HTML Folding', async () => { /*13*/'', /*14*/'', ]; - await assertRanges(input, [r(0, 13), r(1, 12), r(2, 6), r(3, 6), r(8, 11), r(9, 11)]); + await assertRanges(input, [r(0, 13), r(1, 12), r(2, 6), r(3, 6), r(8, 11), r(9, 11), r(9, 11)]); }); test('Embedded JavaScript - incomplete', async () => { diff --git a/extensions/html-language-features/server/test/index.js b/extensions/html-language-features/server/test/index.js index d177599c624..5f7aa21e58a 100644 --- a/extensions/html-language-features/server/test/index.js +++ b/extensions/html-language-features/server/test/index.js @@ -21,7 +21,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 42cef380a66..dc001b1ada8 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -721,10 +721,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -vscode-css-languageservice@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.3.0.tgz#40c797d664ab6188cace33cfbb19b037580a9318" - integrity sha512-BkQAMz4oVHjr0oOAz5PdeE72txlLQK7NIwzmclfr+b6fj6I8POwB+VoXvrZLTbWt9hWRgfvgiQRkh5JwrjPJ5A== +vscode-css-languageservice@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.3.1.tgz#a78755b28b8a0cbb1681121f0fa372860f34ef6b" + integrity sha512-Vdz2cyoTP2tLWikhFdouK8dAQ3gVhLPxsFkIscM30Quh6rd/YejTeZEYC/W+b0iKumHYebDeo1GUFbf0ptySRw== dependencies: vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-types "3.16.0-next.2" diff --git a/extensions/html/package.json b/extensions/html/package.json index 065eb26669b..6b1eac2d702 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -20,6 +20,7 @@ ".htm", ".shtml", ".xhtml", + ".xht", ".mdoc", ".jsp", ".asp", diff --git a/extensions/image-preview/.vscodeignore b/extensions/image-preview/.vscodeignore index 30d948fbc66..bcb886a094d 100644 --- a/extensions/image-preview/.vscodeignore +++ b/extensions/image-preview/.vscodeignore @@ -4,6 +4,7 @@ tsconfig.json out/test/** out/** extension.webpack.config.js +extension-browser.webpack.config.js cgmanifest.json yarn.lock preview-src/** diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index dd04cc77771..064ada94858 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -4,7 +4,8 @@ "description": "%description%", "extensionKind": [ "ui", - "workspace" + "workspace", + "web" ], "version": "1.0.0", "publisher": "vscode", diff --git a/extensions/ini/package.json b/extensions/ini/package.json index cc5ca5da606..24d86072749 100644 --- a/extensions/ini/package.json +++ b/extensions/ini/package.json @@ -18,8 +18,8 @@ }, { "id": "properties", - "extensions": [ ".properties", ".cfg", ".conf", ".directory" ], - "filenames": [ ".gitattributes", ".gitconfig", "gitconfig", ".gitmodules", ".editorconfig" ], + "extensions": [ ".properties", ".cfg", ".conf", ".directory", ".gitattributes", ".gitconfig", ".gitmodules", ".editorconfig" ], + "filenames": [ "gitconfig" ], "filenamePatterns": [ "**/.config/git/config", "**/.git/config" ], "aliases": [ "Properties", "properties" ], "configuration": "./properties.language-configuration.json" diff --git a/extensions/javascript/snippets/javascript.code-snippets b/extensions/javascript/snippets/javascript.code-snippets index fc892b57e92..b005c80c844 100644 --- a/extensions/javascript/snippets/javascript.code-snippets +++ b/extensions/javascript/snippets/javascript.code-snippets @@ -180,14 +180,14 @@ "Log warning to console": { "prefix": "warn", "body": [ - "console.warn($1);", + "console.warn($1);" ], "description": "Log warning to the console" }, "Log error to console": { "prefix": "error", "body": [ - "console.error($1);", + "console.error($1);" ], "description": "Log error to the console" } diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index eb2b984af06..e3e507c7b6c 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,7 +14,7 @@ "dependencies": { "jsonc-parser": "^2.2.1", "request-light": "^0.3.0", - "vscode-json-languageservice": "^3.7.0", + "vscode-json-languageservice": "^3.8.0", "vscode-languageserver": "7.0.0-next.3", "vscode-uri": "^2.1.2" }, diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index e7dffe1d702..281f8276eb3 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -80,10 +80,10 @@ request-light@^0.3.0: https-proxy-agent "^2.2.4" vscode-nls "^4.1.1" -vscode-json-languageservice@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.7.0.tgz#0174417f139cf41dd60c84538fd052385bfb46f6" - integrity sha512-nGLqcBhTjdfkl8Dz9sYGK/ZCTjscYFoIjYw+qqkWB+vyNfM0k/AyIoT73DQvB/PArteCKjEVfQUF72GRZEDSbQ== +vscode-json-languageservice@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.8.0.tgz#c7e7283f993e3db39fa5501407b023ada6fd3ae3" + integrity sha512-sYz5JElJMIlPoqhrRfG3VKnDjnPinLdblIiEVsJgTz1kj2hWD2q5BSbo+evH/5/jKDXDLfA8kb0lHC4vd5g5zg== dependencies: jsonc-parser "^2.2.1" vscode-languageserver-textdocument "^1.0.1" diff --git a/extensions/markdown-language-features/.vscodeignore b/extensions/markdown-language-features/.vscodeignore index bcb886a094d..9f1e0620775 100644 --- a/extensions/markdown-language-features/.vscodeignore +++ b/extensions/markdown-language-features/.vscodeignore @@ -1,4 +1,5 @@ test/** +test-workspace/** src/** tsconfig.json out/test/** diff --git a/extensions/markdown-language-features/media/index.js b/extensions/markdown-language-features/media/index.js index 4075748e35b..0433f33c89a 100644 --- a/extensions/markdown-language-features/media/index.js +++ b/extensions/markdown-language-features/media/index.js @@ -1 +1 @@ -!function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=3)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});let o=void 0;function i(e){const t=document.getElementById("vscode-markdown-preview-data");if(t){const n=t.getAttribute(e);if(n)return JSON.parse(n)}throw new Error(`Could not load data for ${e}`)}t.getData=i,t.getSettings=function(){if(o)return o;if(o=i("data-settings"))return o;throw new Error("Could not load settings")}},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(0),i="code-line";function r(e){return t=0,n=o.getSettings().lineCount-1,i=e,Math.min(n,Math.max(t,i));var t,n,i}const c=(()=>{let e;return()=>{if(!e){e=[{element:document.body,line:0}];for(const t of document.getElementsByClassName(i)){const n=+t.getAttribute("data-line");isNaN(n)||("CODE"===t.tagName&&t.parentElement&&"PRE"===t.parentElement.tagName?e.push({element:t.parentElement,line:n}):e.push({element:t,line:n}))}}return e}})();function s(e){const t=Math.floor(e),n=c();let o=n[0]||null;for(const e of n){if(e.line===t)return{previous:e,next:void 0};if(e.line>t)return{previous:o,next:e};o=e}return{previous:o}}function a(e){const t=c(),n=e-window.scrollY;let o=-1,i=t.length-1;for(;o+1=n?i=e:o=e}const r=t[i],s=u(r);if(i>=1&&s.top>n){return{previous:t[o],next:r}}return i>1&&in?{previous:r,next:t[i+1]}:{previous:r}}function u({element:e}){const t=e.getBoundingClientRect(),n=e.querySelector(`.${i}`);if(n){const e=n.getBoundingClientRect(),o=Math.max(1,e.top-t.top);return{top:t.top,height:o}}return t}t.getElementsForSourceLine=s,t.getLineElementsAtPageOffset=a,t.scrollToRevealSourceLine=function(e){if(!o.getSettings().scrollPreviewWithEditor)return;if(e<=0)return void window.scroll(window.scrollX,0);const{previous:t,next:n}=s(e);if(!t)return;let i=0;const r=u(t),c=r.top;if(n&&n.line!==t.line){i=c+(e-t.line)/(n.line-t.line)*(n.element.getBoundingClientRect().top-c)}else{const t=e-Math.floor(e);i=c+r.height*t}window.scroll(window.scrollX,Math.max(1,window.scrollY+i))},t.getEditorLineNumberForPageOffset=function(e){const{previous:t,next:n}=a(e);if(t){const o=u(t),i=e-window.scrollY-o.top;if(n){const e=i/(u(n).top-o.top);return r(t.line+e*(n.line-t.line))}{const e=i/o.height;return r(t.line+e)}}return null},t.getLineElementForFragment=function(e){return c().find(t=>t.element.id===e)}},function(e,t,n){"use strict";(function(e){Object.defineProperty(t,"__esModule",{value:!0});const o=n(7),i=n(8),r=n(9),c=n(2),s=n(0),a=n(10);let u=!0;const l=new o.ActiveLineMarker,f=s.getSettings(),d=acquireVsCodeApi(),m=d.getState(),p={..."object"==typeof m?m:{},...s.getData("data-state")};d.setState(p);const g=r.createPosterForVsCode(d);window.cspAlerter.setPoster(g),window.styleLoadingMonitor.setPoster(g),window.onload=()=>{v()},i.onceDocumentLoaded(()=>{const t=p.scrollProgress;"number"!=typeof t||f.fragment?f.scrollPreviewWithEditor&&e(()=>{if(f.fragment){p.fragment=void 0,d.setState(p);const e=c.getLineElementForFragment(f.fragment);e&&(u=!0,c.scrollToRevealSourceLine(e.line))}else isNaN(f.line)||(u=!0,c.scrollToRevealSourceLine(f.line))}):e(()=>{u=!0,window.scrollTo(0,t*document.body.clientHeight)})});const h=(()=>{const e=a(e=>{u=!0,c.scrollToRevealSourceLine(e)},50);return t=>{isNaN(t)||(p.line=t,e(t))}})();let v=a(()=>{const e=[];let t=document.getElementsByTagName("img");if(t){let n;for(n=0;n{u=!0,w(),v()},!0),window.addEventListener("message",e=>{if(e.data.source===f.source)switch(e.data.type){case"onDidChangeTextEditorSelection":l.onDidChangeTextEditorSelection(e.data.line);break;case"updateView":h(e.data.line)}},!1),document.addEventListener("dblclick",e=>{if(!f.doubleClickToSwitchToEditor)return;for(let t=e.target;t;t=t.parentNode)if("A"===t.tagName)return;const t=e.pageY,n=c.getEditorLineNumberForPageOffset(t);"number"!=typeof n||isNaN(n)||g.postMessage("didClick",{line:Math.floor(n)})});const y=["http:","https:","mailto:","vscode:","vscode-insiders:"];function w(){p.scrollProgress=window.scrollY/document.body.clientHeight,d.setState(p)}document.addEventListener("click",e=>{if(!e)return;let t=e.target;for(;t;){if(t.tagName&&"A"===t.tagName&&t.href){if(t.getAttribute("href").startsWith("#"))return;if(y.some(e=>t.href.startsWith(e)))return;const n=t.getAttribute("data-href")||t.getAttribute("href");return/^[a-z\-]+:/i.test(n)?void 0:(g.postMessage("openLink",{href:n}),e.preventDefault(),void e.stopPropagation())}t=t.parentNode}},!0),window.addEventListener("scroll",a(()=>{if(w(),u)u=!1;else{const e=c.getEditorLineNumberForPageOffset(window.scrollY);"number"!=typeof e||isNaN(e)||g.postMessage("revealLine",{line:e})}},50))}).call(this,n(4).setImmediate)},function(e,t,n){(function(e){var o=Function.prototype.apply;function i(e,t){this._id=e,this._clearFn=t}t.setTimeout=function(){return new i(o.call(setTimeout,window,arguments),clearTimeout)},t.setInterval=function(){return new i(o.call(setInterval,window,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(window,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout((function(){e._onTimeout&&e._onTimeout()}),t))},n(5),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,n(1))},function(e,t,n){(function(e,t){!function(e,n){"use strict";if(!e.setImmediate){var o,i,r,c,s,a=1,u={},l=!1,f=e.document,d=Object.getPrototypeOf&&Object.getPrototypeOf(e);d=d&&d.setTimeout?d:e,"[object process]"==={}.toString.call(e.process)?o=function(e){t.nextTick((function(){p(e)}))}:!function(){if(e.postMessage&&!e.importScripts){var t=!0,n=e.onmessage;return e.onmessage=function(){t=!1},e.postMessage("","*"),e.onmessage=n,t}}()?e.MessageChannel?((r=new MessageChannel).port1.onmessage=function(e){p(e.data)},o=function(e){r.port2.postMessage(e)}):f&&"onreadystatechange"in f.createElement("script")?(i=f.documentElement,o=function(e){var t=f.createElement("script");t.onreadystatechange=function(){p(e),t.onreadystatechange=null,i.removeChild(t),t=null},i.appendChild(t)}):o=function(e){setTimeout(p,0,e)}:(c="setImmediate$"+Math.random()+"$",s=function(t){t.source===e&&"string"==typeof t.data&&0===t.data.indexOf(c)&&p(+t.data.slice(c.length))},e.addEventListener?e.addEventListener("message",s,!1):e.attachEvent("onmessage",s),o=function(t){e.postMessage(c+t,"*")}),d.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n1)for(var n=1;nnew class{postMessage(t,n){e.postMessage({type:t,source:o.getSettings().source,body:n})}}},function(e,t,n){(function(t){var n="Expected a function",o=NaN,i="[object Symbol]",r=/^\s+|\s+$/g,c=/^[-+]0x[0-9a-f]+$/i,s=/^0b[01]+$/i,a=/^0o[0-7]+$/i,u=parseInt,l="object"==typeof t&&t&&t.Object===Object&&t,f="object"==typeof self&&self&&self.Object===Object&&self,d=l||f||Function("return this")(),m=Object.prototype.toString,p=Math.max,g=Math.min,h=function(){return d.Date.now()};function v(e,t,o){var i,r,c,s,a,u,l=0,f=!1,d=!1,m=!0;if("function"!=typeof e)throw new TypeError(n);function v(t){var n=i,o=r;return i=r=void 0,l=t,s=e.apply(o,n)}function b(e){var n=e-u;return void 0===u||n>=t||n<0||d&&e-l>=c}function T(){var e=h();if(b(e))return E(e);a=setTimeout(T,function(e){var n=t-(e-u);return d?g(n,c-(e-l)):n}(e))}function E(e){return a=void 0,m&&i?v(e):(i=r=void 0,s)}function _(){var e=h(),n=b(e);if(i=arguments,r=this,u=e,n){if(void 0===a)return function(e){return l=e,a=setTimeout(T,t),f?v(e):s}(u);if(d)return a=setTimeout(T,t),v(u)}return void 0===a&&(a=setTimeout(T,t)),s}return t=w(t)||0,y(o)&&(f=!!o.leading,c=(d="maxWait"in o)?p(w(o.maxWait)||0,t):c,m="trailing"in o?!!o.trailing:m),_.cancel=function(){void 0!==a&&clearTimeout(a),l=0,i=u=r=a=void 0},_.flush=function(){return void 0===a?s:E(h())},_}function y(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function w(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&m.call(e)==i}(e))return o;if(y(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=y(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(r,"");var n=s.test(e);return n||a.test(e)?u(e.slice(2),n?2:8):c.test(e)?o:+e}e.exports=function(e,t,o){var i=!0,r=!0;if("function"!=typeof e)throw new TypeError(n);return y(o)&&(i="leading"in o?!!o.leading:i,r="trailing"in o?!!o.trailing:r),v(e,t,{leading:i,maxWait:t,trailing:r})}}).call(this,n(1))}]); \ No newline at end of file +!function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=3)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});let o=void 0;function i(e){const t=document.getElementById("vscode-markdown-preview-data");if(t){const n=t.getAttribute(e);if(n)return JSON.parse(n)}throw new Error(`Could not load data for ${e}`)}t.getData=i,t.getSettings=function(){if(o)return o;if(o=i("data-settings"))return o;throw new Error("Could not load settings")}},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(0),i="code-line";function r(e){return t=0,n=o.getSettings().lineCount-1,i=e,Math.min(n,Math.max(t,i));var t,n,i}const c=(()=>{let e;return()=>{if(!e){e=[{element:document.body,line:0}];for(const t of document.getElementsByClassName(i)){const n=+t.getAttribute("data-line");isNaN(n)||("CODE"===t.tagName&&t.parentElement&&"PRE"===t.parentElement.tagName?e.push({element:t.parentElement,line:n}):e.push({element:t,line:n}))}}return e}})();function s(e){const t=Math.floor(e),n=c();let o=n[0]||null;for(const e of n){if(e.line===t)return{previous:e,next:void 0};if(e.line>t)return{previous:o,next:e};o=e}return{previous:o}}function a(e){const t=c(),n=e-window.scrollY;let o=-1,i=t.length-1;for(;o+1=n?i=e:o=e}const r=t[i],s=u(r);if(i>=1&&s.top>n){return{previous:t[o],next:r}}return i>1&&in?{previous:r,next:t[i+1]}:{previous:r}}function u({element:e}){const t=e.getBoundingClientRect(),n=e.querySelector(`.${i}`);if(n){const e=n.getBoundingClientRect(),o=Math.max(1,e.top-t.top);return{top:t.top,height:o}}return t}t.getElementsForSourceLine=s,t.getLineElementsAtPageOffset=a,t.scrollToRevealSourceLine=function(e){if(!o.getSettings().scrollPreviewWithEditor)return;if(e<=0)return void window.scroll(window.scrollX,0);const{previous:t,next:n}=s(e);if(!t)return;let i=0;const r=u(t),c=r.top;if(n&&n.line!==t.line){i=c+(e-t.line)/(n.line-t.line)*(n.element.getBoundingClientRect().top-c)}else{const t=e-Math.floor(e);i=c+r.height*t}window.scroll(window.scrollX,Math.max(1,window.scrollY+i))},t.getEditorLineNumberForPageOffset=function(e){const{previous:t,next:n}=a(e);if(t){const o=u(t),i=e-window.scrollY-o.top;if(n){const e=i/(u(n).top-o.top);return r(t.line+e*(n.line-t.line))}{const e=i/o.height;return r(t.line+e)}}return null},t.getLineElementForFragment=function(e){return c().find(t=>t.element.id===e)}},function(e,t,n){"use strict";(function(e){Object.defineProperty(t,"__esModule",{value:!0});const o=n(7),i=n(8),r=n(9),c=n(2),s=n(0),a=n(10);let u=!0;const l=new o.ActiveLineMarker,f=s.getSettings(),d=acquireVsCodeApi(),m=d.getState(),p={..."object"==typeof m?m:{},...s.getData("data-state")};d.setState(p);const g=r.createPosterForVsCode(d);window.cspAlerter.setPoster(g),window.styleLoadingMonitor.setPoster(g),window.onload=()=>{v()},i.onceDocumentLoaded(()=>{const t=p.scrollProgress;"number"!=typeof t||f.fragment?f.scrollPreviewWithEditor&&e(()=>{if(f.fragment){p.fragment=void 0,d.setState(p);const e=c.getLineElementForFragment(f.fragment);e&&(u=!0,c.scrollToRevealSourceLine(e.line))}else isNaN(f.line)||(u=!0,c.scrollToRevealSourceLine(f.line))}):e(()=>{u=!0,window.scrollTo(0,t*document.body.clientHeight)})});const h=(()=>{const e=a(e=>{u=!0,c.scrollToRevealSourceLine(e)},50);return t=>{isNaN(t)||(p.line=t,e(t))}})();let v=a(()=>{const e=[];let t=document.getElementsByTagName("img");if(t){let n;for(n=0;n{u=!0,w(),v()},!0),window.addEventListener("message",e=>{if(e.data.source===f.source)switch(e.data.type){case"onDidChangeTextEditorSelection":l.onDidChangeTextEditorSelection(e.data.line);break;case"updateView":h(e.data.line)}},!1),document.addEventListener("dblclick",e=>{if(!f.doubleClickToSwitchToEditor)return;for(let t=e.target;t;t=t.parentNode)if("A"===t.tagName)return;const t=e.pageY,n=c.getEditorLineNumberForPageOffset(t);"number"!=typeof n||isNaN(n)||g.postMessage("didClick",{line:Math.floor(n)})});const y=["http:","https:","mailto:","vscode:","vscode-insiders:"];function w(){p.scrollProgress=window.scrollY/document.body.clientHeight,d.setState(p)}document.addEventListener("click",e=>{if(!e)return;let t=e.target;for(;t;){if(t.tagName&&"A"===t.tagName&&t.href){if(t.getAttribute("href").startsWith("#"))return;let n=t.getAttribute("data-href");if(!n){if(y.some(e=>t.href.startsWith(e)))return;n=t.getAttribute("href")}return/^[a-z\-]+:/i.test(n)?void 0:(g.postMessage("openLink",{href:n}),e.preventDefault(),void e.stopPropagation())}t=t.parentNode}},!0),window.addEventListener("scroll",a(()=>{if(w(),u)u=!1;else{const e=c.getEditorLineNumberForPageOffset(window.scrollY);"number"!=typeof e||isNaN(e)||g.postMessage("revealLine",{line:e})}},50))}).call(this,n(4).setImmediate)},function(e,t,n){(function(e){var o=Function.prototype.apply;function i(e,t){this._id=e,this._clearFn=t}t.setTimeout=function(){return new i(o.call(setTimeout,window,arguments),clearTimeout)},t.setInterval=function(){return new i(o.call(setInterval,window,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(window,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout((function(){e._onTimeout&&e._onTimeout()}),t))},n(5),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,n(1))},function(e,t,n){(function(e,t){!function(e,n){"use strict";if(!e.setImmediate){var o,i,r,c,s,a=1,u={},l=!1,f=e.document,d=Object.getPrototypeOf&&Object.getPrototypeOf(e);d=d&&d.setTimeout?d:e,"[object process]"==={}.toString.call(e.process)?o=function(e){t.nextTick((function(){p(e)}))}:!function(){if(e.postMessage&&!e.importScripts){var t=!0,n=e.onmessage;return e.onmessage=function(){t=!1},e.postMessage("","*"),e.onmessage=n,t}}()?e.MessageChannel?((r=new MessageChannel).port1.onmessage=function(e){p(e.data)},o=function(e){r.port2.postMessage(e)}):f&&"onreadystatechange"in f.createElement("script")?(i=f.documentElement,o=function(e){var t=f.createElement("script");t.onreadystatechange=function(){p(e),t.onreadystatechange=null,i.removeChild(t),t=null},i.appendChild(t)}):o=function(e){setTimeout(p,0,e)}:(c="setImmediate$"+Math.random()+"$",s=function(t){t.source===e&&"string"==typeof t.data&&0===t.data.indexOf(c)&&p(+t.data.slice(c.length))},e.addEventListener?e.addEventListener("message",s,!1):e.attachEvent("onmessage",s),o=function(t){e.postMessage(c+t,"*")}),d.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n1)for(var n=1;nnew class{postMessage(t,n){e.postMessage({type:t,source:o.getSettings().source,body:n})}}},function(e,t,n){(function(t){var n="Expected a function",o=NaN,i="[object Symbol]",r=/^\s+|\s+$/g,c=/^[-+]0x[0-9a-f]+$/i,s=/^0b[01]+$/i,a=/^0o[0-7]+$/i,u=parseInt,l="object"==typeof t&&t&&t.Object===Object&&t,f="object"==typeof self&&self&&self.Object===Object&&self,d=l||f||Function("return this")(),m=Object.prototype.toString,p=Math.max,g=Math.min,h=function(){return d.Date.now()};function v(e,t,o){var i,r,c,s,a,u,l=0,f=!1,d=!1,m=!0;if("function"!=typeof e)throw new TypeError(n);function v(t){var n=i,o=r;return i=r=void 0,l=t,s=e.apply(o,n)}function b(e){var n=e-u;return void 0===u||n>=t||n<0||d&&e-l>=c}function T(){var e=h();if(b(e))return E(e);a=setTimeout(T,function(e){var n=t-(e-u);return d?g(n,c-(e-l)):n}(e))}function E(e){return a=void 0,m&&i?v(e):(i=r=void 0,s)}function _(){var e=h(),n=b(e);if(i=arguments,r=this,u=e,n){if(void 0===a)return function(e){return l=e,a=setTimeout(T,t),f?v(e):s}(u);if(d)return a=setTimeout(T,t),v(u)}return void 0===a&&(a=setTimeout(T,t)),s}return t=w(t)||0,y(o)&&(f=!!o.leading,c=(d="maxWait"in o)?p(w(o.maxWait)||0,t):c,m="trailing"in o?!!o.trailing:m),_.cancel=function(){void 0!==a&&clearTimeout(a),l=0,i=u=r=a=void 0},_.flush=function(){return void 0===a?s:E(h())},_}function y(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function w(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&m.call(e)==i}(e))return o;if(y(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=y(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(r,"");var n=s.test(e);return n||a.test(e)?u(e.slice(2),n?2:8):c.test(e)?o:+e}e.exports=function(e,t,o){var i=!0,r=!0;if("function"!=typeof e)throw new TypeError(n);return y(o)&&(i="leading"in o?!!o.leading:i,r="trailing"in o?!!o.trailing:r),v(e,t,{leading:i,maxWait:t,trailing:r})}}).call(this,n(1))}]); \ No newline at end of file diff --git a/extensions/markdown-language-features/media/markdown.css b/extensions/markdown-language-features/media/markdown.css index fbab6086d2d..f581cd00252 100644 --- a/extensions/markdown-language-features/media/markdown.css +++ b/extensions/markdown-language-features/media/markdown.css @@ -128,21 +128,12 @@ textarea:focus { } p { - margin-bottom: 1.5em; -} - -li > p { - margin-bottom: 0; -} - -/* don't space 2 paragraphs too far apart */ -p + p { - margin-top: -0.8em; + margin-bottom: 0.7em; } ul, ol { - margin-bottom: 1.5em; + margin-bottom: 0.7em; } hr { diff --git a/extensions/markdown-language-features/preview-src/index.ts b/extensions/markdown-language-features/preview-src/index.ts index 4571699f762..064c30ac969 100644 --- a/extensions/markdown-language-features/preview-src/index.ts +++ b/extensions/markdown-language-features/preview-src/index.ts @@ -163,13 +163,15 @@ document.addEventListener('click', event => { return; } - // Pass through known schemes - if (passThroughLinkSchemes.some(scheme => node.href.startsWith(scheme))) { - return; + let hrefText = node.getAttribute('data-href'); + if (!hrefText) { + // Pass through known schemes + if (passThroughLinkSchemes.some(scheme => node.href.startsWith(scheme))) { + return; + } + hrefText = node.getAttribute('href'); } - const hrefText = node.getAttribute('data-href') || node.getAttribute('href'); - // If original link doesn't look like a url, delegate back to VS Code to resolve if (!/^[a-z\-]+:/i.test(hrefText)) { messaging.postMessage('openLink', { href: hrefText }); diff --git a/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts index 06a71068c2e..8bb509d4565 100644 --- a/extensions/markdown-language-features/src/markdownEngine.ts +++ b/extensions/markdown-language-features/src/markdownEngine.ts @@ -129,7 +129,6 @@ export class MarkdownEngine { } this.currentDocument = document.uri; - this._slugCount = new Map(); const tokens = this.tokenizeString(document.getText(), engine); this._tokenCache.update(document, config, tokens); @@ -137,6 +136,8 @@ export class MarkdownEngine { } private tokenizeString(text: string, engine: MarkdownIt) { + this._slugCount = new Map(); + return engine.parse(text.replace(UNICODE_NEWLINE_REGEX, ''), {}); } @@ -355,4 +356,3 @@ function normalizeHighlightLang(lang: string | undefined) { return lang; } } - diff --git a/extensions/markdown-language-features/src/test/inMemoryDocument.ts b/extensions/markdown-language-features/src/test/inMemoryDocument.ts index c2472e5a4ec..052216f90f5 100644 --- a/extensions/markdown-language-features/src/test/inMemoryDocument.ts +++ b/extensions/markdown-language-features/src/test/inMemoryDocument.ts @@ -22,6 +22,7 @@ export class InMemoryDocument implements vscode.TextDocument { isDirty: boolean = false; isClosed: boolean = false; eol: vscode.EndOfLine = vscode.EndOfLine.LF; + notebook: undefined; get fileName(): string { return this.uri.fsPath; @@ -66,4 +67,4 @@ export class InMemoryDocument implements vscode.TextDocument { save(): never { throw new Error('Method not implemented.'); } -} \ No newline at end of file +} diff --git a/extensions/markdown-language-features/src/test/index.ts b/extensions/markdown-language-features/src/test/index.ts index 77019228745..a6d471ee2c1 100644 --- a/extensions/markdown-language-features/src/test/index.ts +++ b/extensions/markdown-language-features/src/test/index.ts @@ -20,7 +20,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index 7687bd3d14b..008969d899e 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -538,9 +538,9 @@ bluebird@^3.5.5: integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + version "4.11.9" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" + integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== boom@2.x.x: version "2.10.1" @@ -1265,9 +1265,9 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" elliptic@^6.0.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" - integrity sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8= + version "6.5.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" + integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -2099,12 +2099,12 @@ hash-base@^3.0.0: safe-buffer "^5.0.1" hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA== + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== dependencies: inherits "^2.0.3" - minimalistic-assert "^1.0.0" + minimalistic-assert "^1.0.1" hawk@3.1.3, hawk@~3.1.3: version "3.1.3" @@ -2221,16 +2221,21 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -2981,10 +2986,10 @@ mimic-fn@^2.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimalistic-assert@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" - integrity sha1-cCvi3aazf0g2vLP121ZkG2Sh09M= +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" diff --git a/extensions/merge-conflict/.vscodeignore b/extensions/merge-conflict/.vscodeignore index 36e8b0714fa..f071cfb7c71 100644 --- a/extensions/merge-conflict/.vscodeignore +++ b/extensions/merge-conflict/.vscodeignore @@ -2,4 +2,5 @@ src/** tsconfig.json out/** extension.webpack.config.js -yarn.lock \ No newline at end of file +extension-browser.webpack.config.js +yarn.lock diff --git a/extensions/microsoft-authentication/.vscodeignore b/extensions/microsoft-authentication/.vscodeignore index ed3f9d37c1f..46f23a20dba 100644 --- a/extensions/microsoft-authentication/.vscodeignore +++ b/extensions/microsoft-authentication/.vscodeignore @@ -1,10 +1,14 @@ .vscode/** .vscode-test/** out/test/** +out/** +extension.webpack.config.js +extension-browser.webpack.config.js +yarn.lock src/** .gitignore vsc-extension-quickstart.md **/tsconfig.json **/tslint.json **/*.map -**/*.ts \ No newline at end of file +**/*.ts diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index 0794d50127b..81ed5c32e4f 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -15,6 +15,11 @@ "*", "onAuthenticationRequest:microsoft" ], + "extensionKind": [ + "ui", + "workspace", + "web" + ], "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "main": "./out/extension.js", "browser": "./dist/browser/extension.js", diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index 24599f62b22..035c5af7350 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -73,7 +73,7 @@ function parseQuery(uri: vscode.Uri) { }, {}); } -export const onDidChangeSessions = new vscode.EventEmitter(); +export const onDidChangeSessions = new vscode.EventEmitter(); export const REFRESH_NETWORK_FAILURE = 'Network failure'; @@ -339,7 +339,7 @@ export class AzureActiveDirectoryService { } private getCallbackEnvironment(callbackUri: vscode.Uri): string { - if (callbackUri.authority.endsWith('.workspaces.github.com')) { + if (callbackUri.authority.endsWith('.workspaces.github.com') || callbackUri.authority.endsWith('.github.dev')) { return `${callbackUri.authority},`; } @@ -471,7 +471,10 @@ export class AzureActiveDirectoryService { redirect_uri: redirectUrl }); - const result = await fetch(`${loginEndpointUrl}${tenant}/oauth2/v2.0/token`, { + const proxyEndpoints: { [providerId: string]: string } | undefined = await vscode.commands.executeCommand('workbench.getCodeExchangeProxyEndpoints'); + const endpoint = proxyEndpoints && proxyEndpoints['microsoft'] || `${loginEndpointUrl}${tenant}/oauth2/v2.0/token`; + + const result = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', diff --git a/extensions/npm/.vscodeignore b/extensions/npm/.vscodeignore index 27bb76ffd24..7700b94ebb0 100644 --- a/extensions/npm/.vscodeignore +++ b/extensions/npm/.vscodeignore @@ -3,4 +3,5 @@ out/** tsconfig.json .vscode/** extension.webpack.config.js -yarn.lock \ No newline at end of file +extension-browser.webpack.config.js +yarn.lock diff --git a/extensions/npm/package.json b/extensions/npm/package.json index a77b48647cd..aa478b26c9b 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -56,7 +56,6 @@ { "id": "npm", "name": "%view.name%", - "when": "npm:showScriptExplorer", "icon": "images/code.svg", "visibility": "hidden" } @@ -166,14 +165,9 @@ "when": "view == npm && viewItem == script", "group": "inline" }, - { - "command": "npm.runScript", - "when": "view == npm && viewItem == debugScript", - "group": "inline" - }, { "command": "npm.debugScript", - "when": "view == npm && viewItem == debugScript", + "when": "view == npm && viewItem == script", "group": "inline" }, { @@ -237,6 +231,7 @@ "type": "boolean", "default": false, "scope": "resource", + "deprecationMessage": "The NPM Script Explorer is now available in 'Views' menu in the Explorer in all folders.", "description": "%config.npm.enableScriptExplorer%" }, "npm.enableRunFromFolder": { diff --git a/extensions/npm/src/features/bowerJSONContribution.ts b/extensions/npm/src/features/bowerJSONContribution.ts index cd648732fc7..c3a827fd1e1 100644 --- a/extensions/npm/src/features/bowerJSONContribution.ts +++ b/extensions/npm/src/features/bowerJSONContribution.ts @@ -33,7 +33,7 @@ export class BowerJSONContribution implements IJSONContribution { return [{ language: 'json', scheme: '*', pattern: '**/bower.json' }, { language: 'json', scheme: '*', pattern: '**/.bower.json' }]; } - private onlineEnabled() { + private isEnabled() { return !!workspace.getConfiguration('npm').get('fetchOnlinePackageInfo'); } @@ -54,8 +54,11 @@ export class BowerJSONContribution implements IJSONContribution { } public collectPropertySuggestions(_resource: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, collector: ISuggestionsCollector): Thenable | null { + if (!this.isEnabled()) { + return null; + } if ((location.matches(['dependencies']) || location.matches(['devDependencies']))) { - if (currentWord.length > 0 && this.onlineEnabled()) { + if (currentWord.length > 0) { const queryUrl = 'https://registry.bower.io/packages/search/' + encodeURIComponent(currentWord); return this.xhr({ @@ -122,7 +125,10 @@ export class BowerJSONContribution implements IJSONContribution { return null; } - public collectValueSuggestions(_resource: string, location: Location, collector: ISuggestionsCollector): Thenable { + public collectValueSuggestions(_resource: string, location: Location, collector: ISuggestionsCollector): Promise | null { + if (!this.isEnabled()) { + return null; + } if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) { // not implemented. Could be do done calling the bower command. Waiting for web API: https://github.com/bower/registry/issues/26 const proposal = new CompletionItem(localize('json.bower.latest.version', 'latest')); @@ -132,7 +138,7 @@ export class BowerJSONContribution implements IJSONContribution { proposal.documentation = 'The latest version of the package'; collector.add(proposal); } - return Promise.resolve(null); + return null; } public resolveSuggestion(item: CompletionItem): Thenable | null { @@ -149,10 +155,6 @@ export class BowerJSONContribution implements IJSONContribution { } private getInfo(pack: string): Thenable { - if (!this.onlineEnabled()) { - return Promise.resolve(undefined); - } - const queryUrl = 'https://registry.bower.io/packages/' + encodeURIComponent(pack); return this.xhr({ @@ -181,6 +183,9 @@ export class BowerJSONContribution implements IJSONContribution { } public getInfoContribution(_resource: string, location: Location): Thenable | null { + if (!this.isEnabled()) { + return null; + } if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) { const pack = location.path[location.path.length - 1]; if (typeof pack === 'string') { diff --git a/extensions/npm/src/features/jsonContributions.ts b/extensions/npm/src/features/jsonContributions.ts index 3873b2dc31a..071d57b3348 100644 --- a/extensions/npm/src/features/jsonContributions.ts +++ b/extensions/npm/src/features/jsonContributions.ts @@ -25,7 +25,7 @@ export interface IJSONContribution { getDocumentSelector(): DocumentSelector; getInfoContribution(fileName: string, location: Location): Thenable | null; collectPropertySuggestions(fileName: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, result: ISuggestionsCollector): Thenable | null; - collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable; + collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable | null; collectDefaultSuggestions(fileName: string, result: ISuggestionsCollector): Thenable; resolveSuggestion?(item: CompletionItem): Thenable | null; } diff --git a/extensions/npm/src/features/packageJSONContribution.ts b/extensions/npm/src/features/packageJSONContribution.ts index 135b632071c..0e24b45aa28 100644 --- a/extensions/npm/src/features/packageJSONContribution.ts +++ b/extensions/npm/src/features/packageJSONContribution.ts @@ -51,6 +51,10 @@ export class PackageJSONContribution implements IJSONContribution { return Promise.resolve(null); } + private isEnabled() { + return this.canRunNPM || this.onlineEnabled(); + } + private onlineEnabled() { return !!workspace.getConfiguration('npm').get('fetchOnlinePackageInfo'); } @@ -63,7 +67,7 @@ export class PackageJSONContribution implements IJSONContribution { isLast: boolean, collector: ISuggestionsCollector ): Thenable | null { - if (!this.onlineEnabled()) { + if (!this.isEnabled()) { return null; } @@ -180,7 +184,7 @@ export class PackageJSONContribution implements IJSONContribution { } public async collectValueSuggestions(_fileName: string, location: Location, result: ISuggestionsCollector): Promise { - if (!this.onlineEnabled()) { + if (!this.isEnabled()) { return null; } @@ -250,7 +254,7 @@ export class PackageJSONContribution implements IJSONContribution { if (this.canRunNPM) { info = await this.npmView(pack); } - if (!info) { + if (!info && this.onlineEnabled()) { info = await this.npmjsView(pack); } return info; @@ -303,6 +307,9 @@ export class PackageJSONContribution implements IJSONContribution { } public getInfoContribution(_fileName: string, location: Location): Thenable | null { + if (!this.isEnabled()) { + return null; + } if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) { const pack = location.path[location.path.length - 1]; if (typeof pack === 'string') { diff --git a/extensions/npm/src/npmMain.ts b/extensions/npm/src/npmMain.ts index 764be6ea0fc..a92f554b759 100644 --- a/extensions/npm/src/npmMain.ts +++ b/extensions/npm/src/npmMain.ts @@ -8,7 +8,7 @@ import * as vscode from 'vscode'; import { addJSONProviders } from './features/jsonContributions'; import { runSelectedScript, selectAndRunScriptFromFolder } from './commands'; import { NpmScriptsTreeDataProvider } from './npmView'; -import { invalidateTasksCache, NpmTaskProvider, hasPackageJson } from './tasks'; +import { invalidateTasksCache, NpmTaskProvider } from './tasks'; import { invalidateHoverScriptsCache, NpmScriptHoverProvider } from './scriptHover'; let treeDataProvider: NpmScriptsTreeDataProvider | undefined; @@ -44,11 +44,6 @@ export async function activate(context: vscode.ExtensionContext): Promise registerHoverProvider(context); context.subscriptions.push(vscode.commands.registerCommand('npm.runSelectedScript', runSelectedScript)); - - if (await hasPackageJson()) { - vscode.commands.executeCommand('setContext', 'npm:showScriptExplorer', true); - } - context.subscriptions.push(vscode.commands.registerCommand('npm.runScriptFromFolder', selectAndRunScriptFromFolder)); } diff --git a/extensions/npm/src/npmView.ts b/extensions/npm/src/npmView.ts index 0a4908ec440..72ec421f775 100644 --- a/extensions/npm/src/npmView.ts +++ b/extensions/npm/src/npmView.ts @@ -3,18 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { JSONVisitor, visit } from 'jsonc-parser'; import * as path from 'path'; import { - Event, EventEmitter, ExtensionContext, Task2 as Task, - TextDocument, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri, - WorkspaceFolder, commands, window, workspace, tasks, Selection, TaskGroup + commands, Event, EventEmitter, ExtensionContext, + Selection, Task2 as Task, + TaskGroup, tasks, TextDocument, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri, + window, workspace, WorkspaceFolder } from 'vscode'; -import { visit, JSONVisitor } from 'jsonc-parser'; -import { - NpmTaskDefinition, getPackageJsonUriFromTask, getScripts, - isWorkspaceFolder, getTaskName, createTask, extractDebugArgFromScript, startDebugging, isAutoDetectionEnabled -} from './tasks'; import * as nls from 'vscode-nls'; +import { + createTask, getTaskName, isAutoDetectionEnabled, isWorkspaceFolder, NpmTaskDefinition, + startDebugging +} from './tasks'; const localize = nls.loadMessageBundle(); @@ -90,9 +91,6 @@ class NpmScript extends TreeItem { } }; this.contextValue = 'script'; - if (task.group && task.group === TaskGroup.Rebuild) { - this.contextValue = 'debugScript'; - } this.package = packageJson; this.task = task; this.command = commandList[command]; @@ -139,27 +137,8 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider { tasks.executeTask(script.task); } - private extractDebugArg(scripts: any, task: Task): [string, number] | undefined { - return extractDebugArgFromScript(scripts[task.name]); - } - private async debugScript(script: NpmScript) { - let task = script.task; - let uri = getPackageJsonUriFromTask(task); - let scripts = await getScripts(uri!); - - let debugArg = this.extractDebugArg(scripts, task); - if (!debugArg) { - let message = localize('noDebugOptions', 'Could not launch "{0}" for debugging because the scripts lacks a node debug option, e.g. "--inspect-brk".', task.name); - let learnMore = localize('learnMore', 'Learn More'); - let ok = localize('ok', 'OK'); - let result = await window.showErrorMessage(message, { modal: true }, ok, learnMore); - if (result === learnMore) { - commands.executeCommand('vscode.open', Uri.parse('https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_launch-configuration-support-for-npm-and-other-tools')); - } - return; - } - startDebugging(task.name, debugArg[0], debugArg[1], script.getFolder()); + startDebugging(script.task.name, script.getFolder()); } private findScript(document: TextDocument, script?: NpmScript): number { diff --git a/extensions/npm/src/scriptHover.ts b/extensions/npm/src/scriptHover.ts index aa803dbc1d4..f8a5482bef8 100644 --- a/extensions/npm/src/scriptHover.ts +++ b/extensions/npm/src/scriptHover.ts @@ -8,7 +8,7 @@ import { workspace, tasks, Range, HoverProvider, Hover, Position, MarkdownString, Uri } from 'vscode'; import { - createTask, startDebugging, findAllScriptRanges, extractDebugArgFromScript + createTask, startDebugging, findAllScriptRanges } from './tasks'; import * as nls from 'vscode-nls'; @@ -54,11 +54,7 @@ export class NpmScriptHoverProvider implements HoverProvider { let contents: MarkdownString = new MarkdownString(); contents.isTrusted = true; contents.appendMarkdown(this.createRunScriptMarkdown(key, document.uri)); - - let debugArgs = extractDebugArgFromScript(value[2]); - if (debugArgs) { - contents.appendMarkdown(this.createDebugScriptMarkdown(key, document.uri, debugArgs[0], debugArgs[1])); - } + contents.appendMarkdown(this.createDebugScriptMarkdown(key, document.uri)); hover = new Hover(contents); } }); @@ -78,12 +74,10 @@ export class NpmScriptHoverProvider implements HoverProvider { ); } - private createDebugScriptMarkdown(script: string, documentUri: Uri, protocol: string, port: number): string { - let args = { + private createDebugScriptMarkdown(script: string, documentUri: Uri): string { + const args = { documentUri: documentUri, script: script, - protocol: protocol, - port: port }; return this.createMarkdownLink( localize('debugScript', 'Debug Script'), @@ -116,11 +110,9 @@ export class NpmScriptHoverProvider implements HoverProvider { public debugScriptFromHover(args: any) { let script = args.script; let documentUri = args.documentUri; - let protocol = args.protocol; - let port = args.port; let folder = workspace.getWorkspaceFolder(documentUri); if (folder) { - startDebugging(script, protocol, port, folder); + startDebugging(script, folder); } } } diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts index 2f4947de447..040e1f820cc 100644 --- a/extensions/npm/src/tasks.ts +++ b/extensions/npm/src/tasks.ts @@ -249,6 +249,8 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise if (prePostScripts.has(each)) { task.group = TaskGroup.Clean; // hack: use Clean group to tag pre/post scripts } + + // todo@connor4312: all scripts are now debuggable, what is a 'debug script'? if (isDebugScript(scripts![each])) { task.group = TaskGroup.Rebuild; // hack: use Rebuild group to tag debug scripts } @@ -355,44 +357,16 @@ export function runScript(script: string, document: TextDocument) { } } -export function extractDebugArgFromScript(scriptValue: string): [string, number] | undefined { - // matches --debug, --debug=1234, --debug-brk, debug-brk=1234, --inspect, - // --inspect=1234, --inspect-brk, --inspect-brk=1234, - // --inspect=localhost:1245, --inspect=127.0.0.1:1234, --inspect=[aa:1:0:0:0]:1234, --inspect=:1234 - let match = scriptValue.match(/--(inspect|debug)(-brk)?(=((\[[0-9a-fA-F:]*\]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-zA-Z0-9\.]*):)?(\d+))?/); - - if (match) { - if (match[6]) { - return [match[1], parseInt(match[6])]; - } - if (match[1] === 'inspect') { - return [match[1], 9229]; - } - if (match[1] === 'debug') { - return [match[1], 5858]; - } - } - return undefined; -} - -export function startDebugging(scriptName: string, protocol: string, port: number, folder: WorkspaceFolder) { - let p = 'inspector'; - if (protocol === 'debug') { - p = 'legacy'; - } - - let packageManager = getPackageManager(folder); +export function startDebugging(scriptName: string, folder: WorkspaceFolder) { const config: DebugConfiguration = { - type: 'node', + type: 'pwa-node', request: 'launch', name: `Debug ${scriptName}`, - runtimeExecutable: packageManager, + runtimeExecutable: getPackageManager(folder), runtimeArgs: [ 'run', scriptName, ], - port: port, - protocol: p }; if (folder) { diff --git a/extensions/package.json b/extensions/package.json index 69f5ea275b4..4baafc4837c 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,12 +3,9 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "3.9.7" + "typescript": "^4.0.2-insiders.20200818" }, "scripts": { "postinstall": "node ./postinstall" - }, - "devDependencies": { - "rimraf": "^3.0.2" } } diff --git a/extensions/python/.vscodeignore b/extensions/python/.vscodeignore index 4d5a14fc91e..b5c95d0fb64 100644 --- a/extensions/python/.vscodeignore +++ b/extensions/python/.vscodeignore @@ -1,6 +1,8 @@ test/** src/** +out/** tsconfig.json extension.webpack.config.js +extension-browser.webpack.config.js cgmanifest.json -.vscode \ No newline at end of file +.vscode diff --git a/extensions/python/package.json b/extensions/python/package.json index 612fcf76504..e7c75aa4ea1 100644 --- a/extensions/python/package.json +++ b/extensions/python/package.json @@ -9,7 +9,7 @@ "activationEvents": ["onLanguage:python"], "main": "./out/pythonMain", "browser": "./dist/browser/pythonMain", - "extensionKind": [ "ui", "workspace" ], + "extensionKind": [ "ui", "workspace", "web" ], "contributes": { "languages": [{ "id": "python", diff --git a/extensions/vscode-web-playground/.vscodeignore b/extensions/search-result/.vscodeignore similarity index 67% rename from extensions/vscode-web-playground/.vscodeignore rename to extensions/search-result/.vscodeignore index 32fe3f03697..da3d2763686 100644 --- a/extensions/vscode-web-playground/.vscodeignore +++ b/extensions/search-result/.vscodeignore @@ -1,11 +1,6 @@ -.vscode/** -build/** -dist/** -out/** src/** -typings/** -.gitignore -extension-browser.webpack.config.js -extension.webpack.config.js +out/** tsconfig.json +extension.webpack.config.js +extension-browser.webpack.config.js yarn.lock diff --git a/extensions/vscode-web-playground/extension-browser.webpack.config.js b/extensions/search-result/extension-browser.webpack.config.js similarity index 82% rename from extensions/vscode-web-playground/extension-browser.webpack.config.js rename to extensions/search-result/extension-browser.webpack.config.js index dfd50aeff96..10c0a19e356 100644 --- a/extensions/vscode-web-playground/extension-browser.webpack.config.js +++ b/extensions/search-result/extension-browser.webpack.config.js @@ -6,13 +6,17 @@ //@ts-check 'use strict'; -const path = require('path'); + const withBrowserDefaults = require('../shared.webpack.config').browser; +const path = require('path'); module.exports = withBrowserDefaults({ context: __dirname, - node: false, entry: { - extension: './src/extension.ts', + extension: './src/extension.ts' + }, + output: { + filename: 'extension.js', + path: path.join(__dirname, 'dist') } }); diff --git a/extensions/search-result/package.json b/extensions/search-result/package.json index ffb5321ae4d..7b43da243cf 100644 --- a/extensions/search-result/package.json +++ b/extensions/search-result/package.json @@ -12,6 +12,7 @@ "Programming Languages" ], "main": "./out/extension.js", + "browser": "./dist/extension.js", "activationEvents": [ "*" ], diff --git a/extensions/search-result/src/extension.ts b/extensions/search-result/src/extension.ts index abb85dac201..3abaa97de56 100644 --- a/extensions/search-result/src/extension.ts +++ b/extensions/search-result/src/extension.ts @@ -126,6 +126,8 @@ function relativePathToUri(path: string, resultsUri: vscode.Uri): vscode.Uri | u return vscode.Uri.file(pathUtils.join(process.env.HOME!, path.slice(2))); } + const uriFromFolderWithPath = (folder: vscode.WorkspaceFolder, path: string): vscode.Uri => + folder.uri.with({ path: pathUtils.join(folder.uri.fsPath, path) }); if (vscode.workspace.workspaceFolders) { const multiRootFormattedPath = /^(.*) • (.*)$/.exec(path); @@ -133,17 +135,18 @@ function relativePathToUri(path: string, resultsUri: vscode.Uri): vscode.Uri | u const [, workspaceName, workspacePath] = multiRootFormattedPath; const folder = vscode.workspace.workspaceFolders.filter(wf => wf.name === workspaceName)[0]; if (folder) { - return vscode.Uri.file(pathUtils.join(folder.uri.fsPath, workspacePath)); + return uriFromFolderWithPath(folder, workspacePath); } } - else if (vscode.workspace.workspaceFolders.length === 1) { - return vscode.Uri.file(pathUtils.join(vscode.workspace.workspaceFolders[0].uri.fsPath, path)); + return uriFromFolderWithPath(vscode.workspace.workspaceFolders[0], path); } else if (resultsUri.scheme !== 'untitled') { // We're in a multi-root workspace, but the path is not multi-root formatted // Possibly a saved search from a single root session. Try checking if the search result document's URI is in a current workspace folder. const prefixMatch = vscode.workspace.workspaceFolders.filter(wf => resultsUri.toString().startsWith(wf.uri.toString()))[0]; - if (prefixMatch) { return vscode.Uri.file(pathUtils.join(prefixMatch.uri.fsPath, path)); } + if (prefixMatch) { + return uriFromFolderWithPath(prefixMatch, path); + } } } diff --git a/extensions/search-result/syntaxes/generateTMLanguage.js b/extensions/search-result/syntaxes/generateTMLanguage.js index eac084ddbc1..fb74d3696ef 100644 --- a/extensions/search-result/syntaxes/generateTMLanguage.js +++ b/extensions/search-result/syntaxes/generateTMLanguage.js @@ -3,10 +3,9 @@ const mappings = [ ['bat', 'source.batchfile'], ['c', 'source.c'], - ['cc', 'source.cpp'], ['clj', 'source.clojure'], ['coffee', 'source.coffee'], - ['cpp', 'source.cpp'], + ['cpp', 'source.cpp', '\\.(?:cpp|c\\+\\+|cc|cxx|hxx|h\\+\\+|hh)'], ['cs', 'source.cs'], ['cshtml', 'text.html.cshtml'], ['css', 'source.css'], @@ -17,8 +16,7 @@ const mappings = [ ['go', 'source.go'], ['groovy', 'source.groovy'], ['h', 'source.objc'], - ['handlebars', 'text.html.handlebars'], - ['hbs', 'text.html.handlebars'], + ['handlebars', 'text.html.handlebars', '\\.(?:handlebars|hbs)'], ['hlsl', 'source.hlsl'], ['hpp', 'source.objcpp'], ['html', 'text.html.basic'], @@ -35,10 +33,8 @@ const mappings = [ ['md', 'text.html.markdown'], ['mm', 'source.objcpp'], ['p6', 'source.perl.6'], - ['perl', 'source.perl'], + ['perl', 'source.perl', '\\.(?:perl|pl|pm)'], ['php', 'source.php'], - ['pl', 'source.perl'], - ['pm', 'source.perl'], ['ps1', 'source.powershell'], ['pug', 'text.pug'], ['py', 'source.python'], @@ -54,8 +50,7 @@ const mappings = [ ['tsx', 'source.tsx'], ['vb', 'source.asp.vb.net'], ['xml', 'text.xml'], - ['yaml', 'source.yaml'], - ['yml', 'source.yaml'], + ['yaml', 'source.yaml', '\\.(?:ya?ml)'], ]; const scopes = { diff --git a/extensions/search-result/syntaxes/searchResult.tmLanguage.json b/extensions/search-result/syntaxes/searchResult.tmLanguage.json index a8a5557c3e5..e2687fe8a72 100644 --- a/extensions/search-result/syntaxes/searchResult.tmLanguage.json +++ b/extensions/search-result/syntaxes/searchResult.tmLanguage.json @@ -84,9 +84,6 @@ { "include": "#c" }, - { - "include": "#cc" - }, { "include": "#clj" }, @@ -129,9 +126,6 @@ { "include": "#handlebars" }, - { - "include": "#hbs" - }, { "include": "#hlsl" }, @@ -186,12 +180,6 @@ { "include": "#php" }, - { - "include": "#pl" - }, - { - "include": "#pm" - }, { "include": "#ps1" }, @@ -240,9 +228,6 @@ { "include": "#yaml" }, - { - "include": "#yml" - }, { "match": "^(?!\\s)(.*?)([^\\\\\\/\\n]*)(:)$", "name": "meta.resultBlock.search string meta.path.search", @@ -453,92 +438,6 @@ } ] }, - "cc": { - "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.cc)(:)$", - "end": "^(?!\\s)", - "beginCaptures": { - "0": { - "name": "string meta.path.search" - }, - "1": { - "name": "meta.path.dirname.search" - }, - "2": { - "name": "meta.path.basename.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "name": "meta.resultLine.search meta.resultLine.multiLine.search", - "begin": "^ (?:\\s*)((\\d+) )", - "while": "^ (?:\\s*)(?:((\\d+)(:))|((\\d+) ))", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "whileCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - }, - "4": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "5": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "patterns": [ - { - "include": "source.cpp" - } - ] - }, - { - "begin": "^ (?:\\s*)((\\d+)(:))", - "while": "(?=not)possible", - "name": "meta.resultLine.search meta.resultLine.singleLine.search", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "include": "source.cpp" - } - ] - } - ] - }, "clj": { "name": "meta.resultBlock.search", "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.clj)(:)$", @@ -713,7 +612,7 @@ }, "cpp": { "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.cpp)(:)$", + "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.(?:cpp|c\\+\\+|cc|cxx|hxx|h\\+\\+|hh))(:)$", "end": "^(?!\\s)", "beginCaptures": { "0": { @@ -1229,7 +1128,7 @@ }, "dockerfile": { "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*(?:dockerfile|Dockerfile))(:)$", + "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*(?:dockerfile|Dockerfile|containerfile|Containerfile))(:)$", "end": "^(?!\\s)", "beginCaptures": { "0": { @@ -1659,93 +1558,7 @@ }, "handlebars": { "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.handlebars)(:)$", - "end": "^(?!\\s)", - "beginCaptures": { - "0": { - "name": "string meta.path.search" - }, - "1": { - "name": "meta.path.dirname.search" - }, - "2": { - "name": "meta.path.basename.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "name": "meta.resultLine.search meta.resultLine.multiLine.search", - "begin": "^ (?:\\s*)((\\d+) )", - "while": "^ (?:\\s*)(?:((\\d+)(:))|((\\d+) ))", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "whileCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - }, - "4": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "5": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "patterns": [ - { - "include": "text.html.handlebars" - } - ] - }, - { - "begin": "^ (?:\\s*)((\\d+)(:))", - "while": "(?=not)possible", - "name": "meta.resultLine.search meta.resultLine.singleLine.search", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "include": "text.html.handlebars" - } - ] - } - ] - }, - "hbs": { - "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.hbs)(:)$", + "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.(?:handlebars|hbs))(:)$", "end": "^(?!\\s)", "beginCaptures": { "0": { @@ -3207,7 +3020,7 @@ }, "perl": { "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.perl)(:)$", + "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.(?:perl|pl|pm))(:)$", "end": "^(?!\\s)", "beginCaptures": { "0": { @@ -3377,178 +3190,6 @@ } ] }, - "pl": { - "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.pl)(:)$", - "end": "^(?!\\s)", - "beginCaptures": { - "0": { - "name": "string meta.path.search" - }, - "1": { - "name": "meta.path.dirname.search" - }, - "2": { - "name": "meta.path.basename.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "name": "meta.resultLine.search meta.resultLine.multiLine.search", - "begin": "^ (?:\\s*)((\\d+) )", - "while": "^ (?:\\s*)(?:((\\d+)(:))|((\\d+) ))", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "whileCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - }, - "4": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "5": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "patterns": [ - { - "include": "source.perl" - } - ] - }, - { - "begin": "^ (?:\\s*)((\\d+)(:))", - "while": "(?=not)possible", - "name": "meta.resultLine.search meta.resultLine.singleLine.search", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "include": "source.perl" - } - ] - } - ] - }, - "pm": { - "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.pm)(:)$", - "end": "^(?!\\s)", - "beginCaptures": { - "0": { - "name": "string meta.path.search" - }, - "1": { - "name": "meta.path.dirname.search" - }, - "2": { - "name": "meta.path.basename.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "name": "meta.resultLine.search meta.resultLine.multiLine.search", - "begin": "^ (?:\\s*)((\\d+) )", - "while": "^ (?:\\s*)(?:((\\d+)(:))|((\\d+) ))", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "whileCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - }, - "4": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "5": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "patterns": [ - { - "include": "source.perl" - } - ] - }, - { - "begin": "^ (?:\\s*)((\\d+)(:))", - "while": "(?=not)possible", - "name": "meta.resultLine.search meta.resultLine.singleLine.search", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "include": "source.perl" - } - ] - } - ] - }, "ps1": { "name": "meta.resultBlock.search", "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.ps1)(:)$", @@ -4841,93 +4482,7 @@ }, "yaml": { "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.yaml)(:)$", - "end": "^(?!\\s)", - "beginCaptures": { - "0": { - "name": "string meta.path.search" - }, - "1": { - "name": "meta.path.dirname.search" - }, - "2": { - "name": "meta.path.basename.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "name": "meta.resultLine.search meta.resultLine.multiLine.search", - "begin": "^ (?:\\s*)((\\d+) )", - "while": "^ (?:\\s*)(?:((\\d+)(:))|((\\d+) ))", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "whileCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - }, - "4": { - "name": "meta.resultLinePrefix.contextLinePrefix.search" - }, - "5": { - "name": "meta.resultLinePrefix.lineNumber.search" - } - }, - "patterns": [ - { - "include": "source.yaml" - } - ] - }, - { - "begin": "^ (?:\\s*)((\\d+)(:))", - "while": "(?=not)possible", - "name": "meta.resultLine.search meta.resultLine.singleLine.search", - "beginCaptures": { - "0": { - "name": "constant.numeric.integer meta.resultLinePrefix.search" - }, - "1": { - "name": "meta.resultLinePrefix.matchLinePrefix.search" - }, - "2": { - "name": "meta.resultLinePrefix.lineNumber.search" - }, - "3": { - "name": "punctuation.separator" - } - }, - "patterns": [ - { - "include": "source.yaml" - } - ] - } - ] - }, - "yml": { - "name": "meta.resultBlock.search", - "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.yml)(:)$", + "begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.(?:ya?ml))(:)$", "end": "^(?!\\s)", "beginCaptures": { "0": { diff --git a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json index 935573463ee..5140f5ad3d0 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -557,6 +557,65 @@ "foreground": "#D0B344" } }, + { + "name": "Markdown Headings", + "scope": "markup.heading.markdown", + "settings": { + "fontStyle": "bold" + } + }, + { + "name": "Markdown Quote", + "scope": "markup.quote.markdown", + "settings": { + "fontStyle": "italic", + "foreground": "" + } + }, + { + "name": "Markdown Bold", + "scope": "markup.bold.markdown", + "settings": { + "fontStyle": "bold" + } + }, + { + "name": "Markdown Link Title/Description", + "scope": "string.other.link.title.markdown,string.other.link.description.markdown", + "settings": { + "foreground": "#AE81FF" + } + }, + { + "name": "Markdown Underline Link/Image", + "scope": "markup.underline.link.markdown,markup.underline.link.image.markdown", + "settings": { + "foreground": "" + } + }, + { + "name": "Markdown Emphasis", + "scope": "markup.italic.markdown", + "settings": { + "fontStyle": "italic" + } + }, + { + "name": "Markdown Punctuation Definition Link", + "scope": "markup.list.unnumbered.markdown, markup.list.numbered.markdown", + "settings": { + "foreground": "" + } + }, + { + "name": "Markdown List Punctuation", + "scope": [ + "punctuation.definition.list.begin.markdown" + ], + "settings": { + "foreground": "" + } + }, { "scope": "token.info-token", "settings": { diff --git a/extensions/typescript-basics/.vscodeignore b/extensions/typescript-basics/.vscodeignore index 06c7b11c5e6..0a0a50bc3e0 100644 --- a/extensions/typescript-basics/.vscodeignore +++ b/extensions/typescript-basics/.vscodeignore @@ -3,3 +3,4 @@ src/** test/** tsconfig.json cgmanifest.json +syntaxes/Readme.md diff --git a/extensions/typescript-basics/package.json b/extensions/typescript-basics/package.json index 6b8c281538e..e3120789cf6 100644 --- a/extensions/typescript-basics/package.json +++ b/extensions/typescript-basics/package.json @@ -45,7 +45,9 @@ ], "filenamePatterns": [ "tsconfig.*.json", - "tsconfig-*.json" + "jsconfig.*.json", + "tsconfig-*.json", + "jsconfig-*.json" ] } ], diff --git a/extensions/typescript-language-features/.vscodeignore b/extensions/typescript-language-features/.vscodeignore index 1edbc2a7b5e..079f06f08d9 100644 --- a/extensions/typescript-language-features/.vscodeignore +++ b/extensions/typescript-language-features/.vscodeignore @@ -1,8 +1,10 @@ build/** src/** test/** +test-workspace/** out/** tsconfig.json extension.webpack.config.js +extension-browser.webpack.config.js cgmanifest.json yarn.lock diff --git a/extensions/typescript-language-features/cgmanifest.json b/extensions/typescript-language-features/cgmanifest.json index 11b737dc59a..3a011a77078 100644 --- a/extensions/typescript-language-features/cgmanifest.json +++ b/extensions/typescript-language-features/cgmanifest.json @@ -28,7 +28,7 @@ "type": "other", "other": { "name": "Unicode", - "downloadUrl": "http://www.unicode.org/", + "downloadUrl": "https://home.unicode.org/", "version": "12.0.0" } }, diff --git a/extensions/typescript-language-features/extension-browser.webpack.config.js b/extensions/typescript-language-features/extension-browser.webpack.config.js index 560a4bb021e..fd8e5877c3a 100644 --- a/extensions/typescript-language-features/extension-browser.webpack.config.js +++ b/extensions/typescript-language-features/extension-browser.webpack.config.js @@ -22,19 +22,24 @@ module.exports = withBrowserDefaults({ new CopyPlugin({ patterns: [ { - from: 'node_modules/typescript-web-server', - to: 'typescript-web', - transform: (content, absoluteFrom) => { - if (absoluteFrom.endsWith('tsserver.js')) { - return Terser.minify(content.toString()).code; - } - return content; + from: 'node_modules/typescript-web-server/*.d.ts', + to: 'typescript-web/', + flatten: true + }, + ], + }), + // @ts-ignore + new CopyPlugin({ + patterns: [ + { + from: 'node_modules/typescript-web-server/tsserver.js', + to: 'typescript-web/tsserver.web.js', + transform: (content) => { + return Terser.minify(content.toString()).code; + }, transformPath: (targetPath) => { - if (targetPath.endsWith('tsserver.js')) { - return targetPath.replace('tsserver.js', 'tsserver.web.js'); - } - return targetPath; + return targetPath.replace('tsserver.js', 'tsserver.web.js'); } } ], diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 8c5e9a4165e..70ed27503cd 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -689,16 +689,16 @@ "typescript.preferences.includePackageJsonAutoImports": { "type": "string", "enum": [ - "all", - "exclude-dev", - "none" + "auto", + "on", + "off" ], "enumDescriptions": [ - "%typescript.preferences.includePackageJsonAutoImports.all%", - "%typescript.preferences.includePackageJsonAutoImports.excludeDev%", - "%typescript.preferences.includePackageJsonAutoImports.none%" + "%typescript.preferences.includePackageJsonAutoImports.auto%", + "%typescript.preferences.includePackageJsonAutoImports.on%", + "%typescript.preferences.includePackageJsonAutoImports.off%" ], - "default": "exclude-dev", + "default": "auto", "markdownDescription": "%typescript.preferences.includePackageJsonAutoImports%", "scope": "window" }, @@ -1030,10 +1030,10 @@ "background": { "activeOnStart": true, "beginsPattern": { - "regexp": "^\\s*(?:message TS6032:|\\[?\\D*\\d{1,2}[:.]\\d{1,2}[:.]\\d{1,2}\\D*(?:\\]| -)) File change detected\\. Starting incremental compilation\\.\\.\\." + "regexp": "^\\s*(?:message TS6032:|\\[?\\D*\\d{1,2}[:.]\\d{1,2}[:.]\\d{1,2}\\D*(ā”œ\\D*\\d{1,2}\\D+┤)?(?:\\]| -)) File change detected\\. Starting incremental compilation\\.\\.\\." }, "endsPattern": { - "regexp": "^\\s*(?:message TS6042:|\\[?\\D*\\d{1,2}[:.]\\d{1,2}[:.]\\d{1,2}\\D*(?:\\]| -)) (?:Compilation complete\\.|Found \\d+ errors?\\.) Watching for file changes\\." + "regexp": "^\\s*(?:message TS6042:|\\[?\\D*\\d{1,2}[:.]\\d{1,2}[:.]\\d{1,2}\\D*(ā”œ\\D*\\d{1,2}\\D+┤)?(?:\\]| -)) (?:Compilation complete\\.|Found \\d+ errors?\\.) Watching for file changes\\." } } } diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index c59d90a3267..6009e367122 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -9,14 +9,14 @@ "typescript.disableAutomaticTypeAcquisition": "Disables automatic type acquisition. Automatic type acquisition fetches `@types` packages from npm to improve IntelliSense for external libraries.", "typescript.enablePromptUseWorkspaceTsdk": "Enables prompting of users to use the TypeScript version configured in the workspace for Intellisense.", "typescript.tsserver.log": "Enables logging of the TS server to a file. This log can be used to diagnose TS Server issues. The log may contain file paths, source code, and other potentially sensitive information from your project.", - "typescript.tsserver.pluginPaths": "Additional paths to discover TypeScript Language Service plugins. Requires using TypeScript 2.3.0 or newer in the workspace.", + "typescript.tsserver.pluginPaths": "Additional paths to discover TypeScript Language Service plugins.", "typescript.tsserver.pluginPaths.item": "Either an absolute or relative path. Relative path will be resolved against workspace folder(s).", "typescript.tsserver.trace": "Enables tracing of messages sent to the TS server. This trace can be used to diagnose TS Server issues. The trace may contain file paths, source code, and other potentially sensitive information from your project.", "typescript.validate.enable": "Enable/disable TypeScript validation.", "typescript.format.enable": "Enable/disable default TypeScript formatter.", "javascript.format.enable": "Enable/disable default JavaScript formatter.", "format.insertSpaceAfterCommaDelimiter": "Defines space handling after a comma delimiter.", - "format.insertSpaceAfterConstructor": "Defines space handling after the constructor keyword. Requires using TypeScript 2.3.0 or newer in the workspace.", + "format.insertSpaceAfterConstructor": "Defines space handling after the constructor keyword.", "format.insertSpaceAfterSemicolonInForStatements": "Defines space handling after a semicolon in a for statement.", "format.insertSpaceBeforeAndAfterBinaryOperators": "Defines space handling after a binary operator.", "format.insertSpaceAfterKeywordsInControlFlowStatements": "Defines space handling after keywords in a control flow statement.", @@ -24,10 +24,10 @@ "format.insertSpaceBeforeFunctionParenthesis": "Defines space handling before function argument parentheses.", "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Defines space handling after opening and before closing non-empty parenthesis.", "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Defines space handling after opening and before closing non-empty brackets.", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": "Defines space handling after opening and before closing non-empty braces. Requires using TypeScript 2.3.0 or newer in the workspace.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": "Defines space handling after opening and before closing non-empty braces.", "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Defines space handling after opening and before closing template string braces.", "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Defines space handling after opening and before closing JSX expression braces.", - "format.insertSpaceAfterTypeAssertion": "Defines space handling after type assertions in TypeScript. Requires using TypeScript 2.4 or newer in the workspace.", + "format.insertSpaceAfterTypeAssertion": "Defines space handling after type assertions in TypeScript.", "format.placeOpenBraceOnNewLineForFunctions": "Defines whether an open brace is put onto a new line for functions or not.", "format.placeOpenBraceOnNewLineForControlBlocks": "Defines whether an open brace is put onto a new line for control blocks or not.", "format.semicolons": "Defines handling of optional semicolons. Requires using TypeScript 3.7 or newer in the workspace.", @@ -45,8 +45,8 @@ "typescript.restartTsServer": "Restart TS server", "typescript.selectTypeScriptVersion.title": "Select TypeScript Version...", "typescript.reportStyleChecksAsWarnings": "Report style checks as warnings.", - "javascript.implicitProjectConfig.checkJs": "Enable/disable semantic checking of JavaScript files. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.", - "typescript.npm": "Specifies the path to the npm executable used for Automatic Type Acquisition. Requires using TypeScript 2.3.4 or newer in the workspace.", + "javascript.implicitProjectConfig.checkJs": "Enable/disable semantic checking of JavaScript files. Existing jsconfig.json or tsconfig.json files override this setting.", + "typescript.npm": "Specifies the path to the npm executable used for Automatic Type Acquisition.", "typescript.check.npmIsInstalled": "Check if npm is installed for Automatic Type Acquisition.", "configuration.suggest.names": "Enable/disable including unique names from the file in JavaScript suggestions. Note that name suggestions are always disabled in JavaScript code that is semantically checked using `@ts-check` or `checkJs`.", "typescript.tsc.autoDetect": "Controls auto detection of tsc tasks.", @@ -60,13 +60,13 @@ "configuration.tsserver.useSeparateSyntaxServer": "Enable/disable spawning a separate TypeScript server that can more quickly respond to syntax related operations, such as calculating folding or computing document symbols. Requires using TypeScript 3.4.0 or newer in the workspace.", "configuration.tsserver.maxTsServerMemory": "Set the maximum amount of memory (in MB) to allocate to the TypeScript server process", "configuration.tsserver.experimental.enableProjectDiagnostics": "(Experimental) Enables project wide error reporting.", - "typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Requires using TypeScript 2.6.0 or newer in the workspace. Default of `null` uses VS Code's locale.", - "javascript.implicitProjectConfig.experimentalDecorators": "Enable/disable `experimentalDecorators` for JavaScript files that are not part of a project. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.", - "configuration.suggest.autoImports": "Enable/disable auto import suggestions. Requires using TypeScript 2.6.1 or newer in the workspace.", + "typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Default of `null` uses VS Code's locale.", + "javascript.implicitProjectConfig.experimentalDecorators": "Enable/disable `experimentalDecorators` for JavaScript files that are not part of a project. Existing jsconfig.json or tsconfig.json files override this setting.", + "configuration.suggest.autoImports": "Enable/disable auto import suggestions.", "taskDefinition.tsconfig.description": "The tsconfig file that defines the TS build.", - "javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor. Requires using TypeScript 2.8 or newer in the workspace.", - "typescript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for TypeScript files in the editor. Requires using TypeScript 2.8 or newer in the workspace.", - "typescript.preferences.quoteStyle": "Preferred quote style to use for quick fixes: `single` quotes, `double` quotes, or `auto` infer quote type from existing imports. Requires using TypeScript 2.9 or newer in the workspace.", + "javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor.", + "typescript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for TypeScript files in the editor.", + "typescript.preferences.quoteStyle": "Preferred quote style to use for quick fixes: `single` quotes, `double` quotes, or `auto` infer quote type from existing imports.", "typescript.preferences.importModuleSpecifier": "Preferred path style for auto imports.", "typescript.preferences.importModuleSpecifier.auto": "Automatically select import path style. Prefers using a relative import if `baseUrl` is configured and the relative path has fewer segments than the non-relative import.", "typescript.preferences.importModuleSpecifier.relative": "Relative to the file location.", @@ -76,15 +76,15 @@ "typescript.preferences.importModuleSpecifierEnding.minimal": "Shorten `./component/index.js` to `./component`.", "typescript.preferences.importModuleSpecifierEnding.index": "Shorten `./component/index.js` to `./component/index`.", "typescript.preferences.importModuleSpecifierEnding.js": "Do not shorten path endings; include the `.js` extension.", - "typescript.preferences.includePackageJsonAutoImports": "Enable/disable processing `package.json` dependencies for available auto imports.", - "typescript.preferences.includePackageJsonAutoImports.all": "Include all listed dependencies.", - "typescript.preferences.includePackageJsonAutoImports.excludeDev": "Exclude devDependencies.", - "typescript.preferences.includePackageJsonAutoImports.none": "Disable package.json dependency processing.", - "typescript.updateImportsOnFileMove.enabled": "Enable/disable automatic updating of import paths when you rename or move a file in VS Code. Requires using TypeScript 2.9 or newer in the workspace.", + "typescript.preferences.includePackageJsonAutoImports": "Enable/disable searching `package.json` dependencies for available auto imports.", + "typescript.preferences.includePackageJsonAutoImports.auto": "Search dependencies based on estimated performance impact.", + "typescript.preferences.includePackageJsonAutoImports.on": "Always search dependencies.", + "typescript.preferences.includePackageJsonAutoImports.off": "Never search dependencies.", + "typescript.updateImportsOnFileMove.enabled": "Enable/disable automatic updating of import paths when you rename or move a file in VS Code.", "typescript.updateImportsOnFileMove.enabled.prompt": "Prompt on each rename.", "typescript.updateImportsOnFileMove.enabled.always": "Always update paths automatically.", "typescript.updateImportsOnFileMove.enabled.never": "Never rename paths and don't prompt.", - "typescript.autoClosingTags": "Enable/disable automatic closing of JSX tags. Requires using TypeScript 3.0 or newer in the workspace.", + "typescript.autoClosingTags": "Enable/disable automatic closing of JSX tags.", "typescript.suggest.enabled": "Enabled/disable autocomplete suggestions.", "configuration.surveys.enabled": "Enabled/disable occasional surveys that help us improve VS Code's JavaScript and TypeScript support.", "configuration.suggest.completeJSDocs": "Enable/disable suggestion to complete JSDoc comments.", diff --git a/extensions/typescript-language-features/src/extension.browser.ts b/extensions/typescript-language-features/src/extension.browser.ts index f48f2b5071d..9291e22ae36 100644 --- a/extensions/typescript-language-features/src/extension.browser.ts +++ b/extensions/typescript-language-features/src/extension.browser.ts @@ -52,7 +52,7 @@ export function activate( const versionProvider = new StaticVersionProvider( new TypeScriptVersion( TypeScriptVersionSource.Bundled, - '/builtin-extension/typescript-language-features/dist/browser/typescript-web/tsserver.web.js', + context.asAbsolutePath('dist/browser/typescript-web/tsserver.web.js'), API.v400)); const lazyClientHost = createLazyClientHost(context, false, { diff --git a/extensions/typescript-language-features/src/languageFeatures/completions.ts b/extensions/typescript-language-features/src/languageFeatures/completions.ts index 9cac559ef20..96914bc83a7 100644 --- a/extensions/typescript-language-features/src/languageFeatures/completions.ts +++ b/extensions/typescript-language-features/src/languageFeatures/completions.ts @@ -338,14 +338,13 @@ class CompletionAcceptedCommand implements Command { if (item instanceof MyCompletionItem) { /* __GDPR__ "completions.accept" : { - "isPackageJsonImport" : { "classification": "SystemMetadata", "purpose": "FeatureInsight" }, + "isPackageJsonImport" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "${include}": [ "${TypeScriptCommonProperties}" ] } */ this.telemetryReporter.logTelemetry('completions.accept', { - // @ts-expect-error - remove after TS 4.0 protocol update isPackageJsonImport: item.tsEntry.isPackageJsonImport ? 'true' : undefined, }); } @@ -540,7 +539,6 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< for (let entry of entries) { if (!shouldExcludeCompletionEntry(entry, completionConfiguration)) { items.push(new MyCompletionItem(position, document, entry, completionContext, metadata)); - // @ts-expect-error - remove after TS 4.0 protocol update includesPackageJsonImport = !!entry.isPackageJsonImport; } } @@ -557,11 +555,12 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< ) { /* __GDPR__ "completions.execute" : { - "duration" : { "classification": "SystemMetadata", "purpose": "FeatureInsight" }, - "type" : { "classification": "SystemMetadata", "purpose": "FeatureInsight" }, - "count" : { "classification": "SystemMetadata", "purpose": "FeatureInsight" }, - "updateGraphDurationMs" : { "classification": "SystemMetadata", "purpose": "FeatureInsight" }, - "includesPackageJsonImport" : { "classification": "SystemMetadata", "purpose": "FeatureInsight" }, + "duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "updateGraphDurationMs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "createAutoImportProviderProgramDurationMs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "includesPackageJsonImport" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "${include}": [ "${TypeScriptCommonProperties}" ] @@ -572,6 +571,7 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< type: response?.type ?? 'unknown', count: response?.type === 'response' && response.body ? response.body.entries.length : 0, updateGraphDurationMs: response?.type === 'response' ? response.performanceData?.updateGraphDurationMs : undefined, + createAutoImportProviderProgramDurationMs: response?.type === 'response' ? (response.performanceData as Proto.PerformanceData & { createAutoImportProviderProgramDurationMs?: number })?.createAutoImportProviderProgramDurationMs : undefined, includesPackageJsonImport: includesPackageJsonImport ? 'true' : undefined, }); } @@ -641,7 +641,11 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< const { snippet, parameterCount } = snippetForFunctionCall(item, detail.displayParts); item.insertText = snippet; if (parameterCount > 0) { - commands.push({ title: 'triggerParameterHints', command: 'editor.action.triggerParameterHints' }); + //Fix for https://github.com/microsoft/vscode/issues/104059 + //Don't show parameter hints if "editor.parameterHints.enabled": false + if (vscode.workspace.getConfiguration('editor.parameterHints').get('enabled')) { + commands.push({ title: 'triggerParameterHints', command: 'editor.action.triggerParameterHints' }); + } } } } diff --git a/extensions/typescript-language-features/src/languageFeatures/definitions.ts b/extensions/typescript-language-features/src/languageFeatures/definitions.ts index 7c01400c206..6d6e4fc2851 100644 --- a/extensions/typescript-language-features/src/languageFeatures/definitions.ts +++ b/extensions/typescript-language-features/src/languageFeatures/definitions.ts @@ -39,10 +39,10 @@ export default class TypeScriptDefinitionProvider extends DefinitionProviderBase return response.body.definitions .map((location): vscode.DefinitionLink => { const target = typeConverters.Location.fromTextSpan(this.client.toResource(location.file), location); - if ((location as any).contextStart) { + if (location.contextStart && location.contextEnd) { return { originSelectionRange: span, - targetRange: typeConverters.Range.fromLocations((location as any).contextStart, (location as any).contextEnd), + targetRange: typeConverters.Range.fromLocations(location.contextStart, location.contextEnd), targetUri: target.uri, targetSelectionRange: target.range, }; diff --git a/extensions/typescript-language-features/src/languageFeatures/hover.ts b/extensions/typescript-language-features/src/languageFeatures/hover.ts index c6c4860f663..a4de074897f 100644 --- a/extensions/typescript-language-features/src/languageFeatures/hover.ts +++ b/extensions/typescript-language-features/src/languageFeatures/hover.ts @@ -5,7 +5,8 @@ import * as vscode from 'vscode'; import type * as Proto from '../protocol'; -import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; +import { localize } from '../tsServer/versionProvider'; +import { ClientCapability, ITypeScriptServiceClient, ServerType } from '../typescriptService'; import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; import { DocumentSelector } from '../utils/documentSelector'; import { markdownDocumentation } from '../utils/previewer'; @@ -35,17 +36,30 @@ class TypeScriptHoverProvider implements vscode.HoverProvider { } return new vscode.Hover( - TypeScriptHoverProvider.getContents(response.body), + this.getContents(response.body, response._serverType), typeConverters.Range.fromTextSpan(response.body)); } - private static getContents( - data: Proto.QuickInfoResponseBody + private getContents( + data: Proto.QuickInfoResponseBody, + source: ServerType | undefined, ) { - const parts = []; + const parts: vscode.MarkedString[] = []; if (data.displayString) { - parts.push({ language: 'typescript', value: data.displayString }); + const displayParts: string[] = []; + + if (source === ServerType.Syntax && this.client.capabilities.has(ClientCapability.Semantic)) { + displayParts.push( + localize({ + key: 'loadingPrefix', + comment: ['Prefix displayed for hover entries while the server is still loading'] + }, "(loading...)")); + } + + displayParts.push(data.displayString); + + parts.push({ language: 'typescript', value: displayParts.join(' ') }); } parts.push(markdownDocumentation(data.documentation, data.tags)); return parts; diff --git a/extensions/typescript-language-features/src/lazyClientHost.ts b/extensions/typescript-language-features/src/lazyClientHost.ts index 7f136285215..73dee25e6c3 100644 --- a/extensions/typescript-language-features/src/lazyClientHost.ts +++ b/extensions/typescript-language-features/src/lazyClientHost.ts @@ -11,6 +11,7 @@ import { TsServerProcessFactory } from './tsServer/server'; import { ITypeScriptVersionProvider } from './tsServer/versionProvider'; import TypeScriptServiceClientHost from './typeScriptServiceClientHost'; import { flatten } from './utils/arrays'; +import * as fileSchemes from './utils/fileSchemes'; import { standardLanguageDescriptions } from './utils/languageDescription'; import { lazy, Lazy } from './utils/lazy'; import ManagedFileContextManager from './utils/managedFileContext'; @@ -85,5 +86,6 @@ function isSupportedDocument( supportedLanguage: readonly string[], document: vscode.TextDocument ): boolean { - return supportedLanguage.indexOf(document.languageId) >= 0; + return supportedLanguage.indexOf(document.languageId) >= 0 + && !fileSchemes.disabledSchemes.has(document.uri.scheme); } diff --git a/extensions/typescript-language-features/src/protocol.d.ts b/extensions/typescript-language-features/src/protocol.d.ts index 6e926eb8d7e..e81fe81f2db 100644 --- a/extensions/typescript-language-features/src/protocol.d.ts +++ b/extensions/typescript-language-features/src/protocol.d.ts @@ -1,2 +1,12 @@ import * as Proto from 'typescript/lib/protocol'; export = Proto; + +declare enum ServerType { + Syntax = 'syntax', + Semantic = 'semantic', +} +declare module 'typescript/lib/protocol' { + interface Response { + readonly _serverType?: ServerType; + } +} diff --git a/extensions/typescript-language-features/src/test/functionCallSnippet.test.ts b/extensions/typescript-language-features/src/test/functionCallSnippet.test.ts index 1289b87b4bc..5c8cf18c73c 100644 --- a/extensions/typescript-language-features/src/test/functionCallSnippet.test.ts +++ b/extensions/typescript-language-features/src/test/functionCallSnippet.test.ts @@ -128,4 +128,13 @@ suite('typescript function call snippets', () => { ).snippet.value, 'foobar(${1:param})$0'); }); + + test('Should skip over this parameter', async () => { + assert.strictEqual( + snippetForFunctionCall( + { label: 'foobar', }, + [{ "text": "function", "kind": "keyword" }, { "text": " ", "kind": "space" }, { "text": "foobar", "kind": "functionName" }, { "text": "(", "kind": "punctuation" }, { "text": "this", "kind": "parameterName" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "string", "kind": "keyword" }, { "text": ",", "kind": "punctuation" }, { "text": "param", "kind": "parameterName" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "string", "kind": "keyword" }, { "text": ")", "kind": "punctuation" }, { "text": ":", "kind": "punctuation" }, { "text": " ", "kind": "space" }, { "text": "void", "kind": "keyword" }] + ).snippet.value, + 'foobar(${1:param})$0'); + }); }); diff --git a/extensions/typescript-language-features/src/test/server.test.ts b/extensions/typescript-language-features/src/test/server.test.ts index 7e27e366b5c..5caad737a48 100644 --- a/extensions/typescript-language-features/src/test/server.test.ts +++ b/extensions/typescript-language-features/src/test/server.test.ts @@ -9,6 +9,7 @@ import * as stream from 'stream'; import type * as Proto from '../protocol'; import { NodeRequestCanceller } from '../tsServer/cancellation.electron'; import { ProcessBasedTsServer, TsServerProcess } from '../tsServer/server'; +import { ServerType } from '../typescriptService'; import { nulToken } from '../utils/cancellation'; import { Logger } from '../utils/logger'; import { TelemetryReporter } from '../utils/telemetry'; @@ -64,7 +65,7 @@ suite('Server', () => { test('should send requests with increasing sequence numbers', async () => { const process = new FakeServerProcess(); - const server = new ProcessBasedTsServer('semantic', process, undefined, new NodeRequestCanceller('semantic', tracer), undefined!, NoopTelemetryReporter, tracer); + const server = new ProcessBasedTsServer('semantic', ServerType.Semantic, process, undefined, new NodeRequestCanceller('semantic', tracer), undefined!, NoopTelemetryReporter, tracer); const onWrite1 = process.onWrite(); server.executeImpl('geterr', {}, { isAsync: false, token: nulToken, expectsResult: true }); diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index fc7841322bd..6ad3d015679 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -9,7 +9,7 @@ import { EventName } from '../protocol.const'; import { CallbackMap } from '../tsServer/callbackMap'; import { RequestItem, RequestQueue, RequestQueueingType } from '../tsServer/requestQueue'; import { TypeScriptServerError } from '../tsServer/serverError'; -import { ServerResponse, TypeScriptRequests } from '../typescriptService'; +import { ServerResponse, ServerType, TypeScriptRequests } from '../typescriptService'; import { TypeScriptServiceConfiguration } from '../utils/configuration'; import { Disposable } from '../utils/dispose'; import { TelemetryReporter } from '../utils/telemetry'; @@ -77,6 +77,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe constructor( private readonly _serverId: string, + private readonly _serverSource: ServerType, private readonly _process: TsServerProcess, private readonly _tsServerLogFile: string | undefined, private readonly _requestCanceller: OngoingRequestCanceller, @@ -130,7 +131,14 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe try { switch (message.type) { case 'response': - this.dispatchResponse(message as Proto.Response); + if (this._serverSource) { + this.dispatchResponse({ + ...(message as Proto.Response), + _serverType: this._serverSource + }); + } else { + this.dispatchResponse(message as Proto.Response); + } break; case 'event': diff --git a/extensions/typescript-language-features/src/tsServer/serverError.ts b/extensions/typescript-language-features/src/tsServer/serverError.ts index 1e7ab7672d7..2653360c9be 100644 --- a/extensions/typescript-language-features/src/tsServer/serverError.ts +++ b/extensions/typescript-language-features/src/tsServer/serverError.ts @@ -18,7 +18,7 @@ export class TypeScriptServerError extends Error { } private constructor( - serverId: string, + public readonly serverId: string, public readonly version: TypeScriptVersion, private readonly response: Proto.Response, public readonly serverMessage: string | undefined, @@ -38,11 +38,13 @@ export class TypeScriptServerError extends Error { /* __GDPR__FRAGMENT__ "TypeScriptRequestErrorProperties" : { "command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "serverid" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "sanitizedstack" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } } */ return { command: this.serverCommand, + serverid: this.serverId, sanitizedstack: this.sanitizedStack || '', } as const; } diff --git a/extensions/typescript-language-features/src/tsServer/spawner.ts b/extensions/typescript-language-features/src/tsServer/spawner.ts index a3187efc35e..7f4aaeefe13 100644 --- a/extensions/typescript-language-features/src/tsServer/spawner.ts +++ b/extensions/typescript-language-features/src/tsServer/spawner.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import * as vscode from 'vscode'; import { OngoingRequestCancellerFactory } from '../tsServer/cancellation'; -import { ClientCapabilities, ClientCapability } from '../typescriptService'; +import { ClientCapabilities, ClientCapability, ServerType } from '../typescriptService'; import API from '../utils/api'; import { SeparateSyntaxServerConfiguration, TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration'; import { Logger } from '../utils/logger'; @@ -143,6 +143,7 @@ export class TypeScriptServerSpawner { return new ProcessBasedTsServer( kind, + this.kindToServerType(kind), process!, tsServerLogFile, canceller, @@ -151,6 +152,19 @@ export class TypeScriptServerSpawner { this._tracer); } + private kindToServerType(kind: TsServerProcessKind): ServerType { + switch (kind) { + case TsServerProcessKind.Syntax: + return ServerType.Syntax; + + case TsServerProcessKind.Main: + case TsServerProcessKind.Semantic: + case TsServerProcessKind.Diagnostics: + default: + return ServerType.Semantic; + } + } + private getTsServerArgs( kind: TsServerProcessKind, configuration: TypeScriptServiceConfiguration, @@ -163,7 +177,11 @@ export class TypeScriptServerSpawner { let tsServerLogFile: string | undefined; if (kind === TsServerProcessKind.Syntax) { - args.push('--syntaxOnly'); + if (apiVersion.gte(API.v401)) { + args.push('--serverMode', 'partialSemantic'); + } else { + args.push('--syntaxOnly'); + } } if (apiVersion.gte(API.v250)) { diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index de32927d816..8a59d97105c 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -13,6 +13,11 @@ import { TypeScriptServiceConfiguration } from './utils/configuration'; import { PluginManager } from './utils/plugins'; import { TelemetryReporter } from './utils/telemetry'; +export enum ServerType { + Syntax = 'syntax', + Semantic = 'semantic', +} + export namespace ServerResponse { export class Cancelled { diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 3f086292310..a9e6bf10d7f 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -366,6 +366,12 @@ export default class TypeScriptServiceClient extends Disposable implements IType } let version = this._versionManager.currentVersion; + if (!version.isValid) { + vscode.window.showWarningMessage(localize('noServerFound', 'The path {0} doesn\'t point to a valid tsserver install. Falling back to bundled TypeScript version.', version.path)); + + this._versionManager.reset(); + version = this._versionManager.currentVersion; + } this.info(`Using tsserver from: ${version.path}`); @@ -526,7 +532,6 @@ export default class TypeScriptServiceClient extends Disposable implements IType preferences: { providePrefixAndSuffixTextForRename: true, allowRenameOfImportPath: true, - // @ts-expect-error, remove after 4.0 protocol update includePackageJsonAutoImports: this._configuration.includePackageJsonAutoImports, }, watchOptions @@ -631,6 +636,10 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public normalizedPath(resource: vscode.Uri): string | undefined { + if (fileSchemes.disabledSchemes.has(resource.scheme)) { + return undefined; + } + switch (resource.scheme) { case fileSchemes.file: { @@ -643,10 +652,6 @@ export default class TypeScriptServiceClient extends Disposable implements IType // Both \ and / must be escaped in regular expressions return result.replace(new RegExp('\\' + this.pathSeparator, 'g'), '/'); } - case fileSchemes.git: - { - return undefined; - } default: { return this.inMemoryResourcePrefix + resource.toString(true); @@ -660,7 +665,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType public toOpenedFilePath(document: vscode.TextDocument): string | undefined { if (!this.bufferSyncSupport.ensureHasBuffer(document.uri)) { - console.error(`Unexpected resource ${document.uri}`); + if (!fileSchemes.disabledSchemes.has(document.uri.scheme)) { + console.error(`Unexpected resource ${document.uri}`); + } return undefined; } return this.toPath(document.uri) || undefined; @@ -946,7 +953,7 @@ The log file may contain personal data, including full paths and source code fro sections.push(`**TS Server Log** -Server logging disabled. To help us fix crashes like this, please enable logging by setting: +ā—ļøServer logging disabled. To help us fix crashes like this, please enable logging by setting: \`\`\`json "typescript.tsserver.log": "verbose" @@ -957,6 +964,8 @@ After enabling this setting, future crash reports will include the server log.`) sections.push(`**TS Server Error Stack** +Server: \`${error.serverId}\` + \`\`\` ${error.serverStack} \`\`\``); diff --git a/extensions/typescript-language-features/src/utils/api.ts b/extensions/typescript-language-features/src/utils/api.ts index 2a72b19004c..289c091f5b1 100644 --- a/extensions/typescript-language-features/src/utils/api.ts +++ b/extensions/typescript-language-features/src/utils/api.ts @@ -35,6 +35,7 @@ export default class API { public static readonly v381 = API.fromSimpleString('3.8.1'); public static readonly v390 = API.fromSimpleString('3.9.0'); public static readonly v400 = API.fromSimpleString('4.0.0'); + public static readonly v401 = API.fromSimpleString('4.0.1'); public static fromVersionString(versionString: string): API { let version = semver.valid(versionString); diff --git a/extensions/typescript-language-features/src/utils/configuration.ts b/extensions/typescript-language-features/src/utils/configuration.ts index cde1e14b9a0..f549ff6f9e2 100644 --- a/extensions/typescript-language-features/src/utils/configuration.ts +++ b/extensions/typescript-language-features/src/utils/configuration.ts @@ -66,7 +66,7 @@ export class TypeScriptServiceConfiguration { public readonly maxTsServerMemory: number; public readonly enablePromptUseWorkspaceTsdk: boolean; public readonly watchOptions: protocol.WatchOptions | undefined; - public readonly includePackageJsonAutoImports: string | undefined; + public readonly includePackageJsonAutoImports: 'auto' | 'on' | 'off' | undefined; public static loadFromWorkspace(): TypeScriptServiceConfiguration { return new TypeScriptServiceConfiguration(); @@ -181,8 +181,8 @@ export class TypeScriptServiceConfiguration { return configuration.get('typescript.tsserver.watchOptions'); } - private static readIncludePackageJsonAutoImports(configuration: vscode.WorkspaceConfiguration): string | undefined { - return configuration.get('typescript.preferences.includePackageJsonAutoImports'); + private static readIncludePackageJsonAutoImports(configuration: vscode.WorkspaceConfiguration): 'auto' | 'on' | 'off' | undefined { + return configuration.get<'auto' | 'on' | 'off'>('typescript.preferences.includePackageJsonAutoImports'); } private static readMaxTsServerMemory(configuration: vscode.WorkspaceConfiguration): number { diff --git a/extensions/typescript-language-features/src/utils/fileSchemes.ts b/extensions/typescript-language-features/src/utils/fileSchemes.ts index 4e94d547bd6..d465a60326e 100644 --- a/extensions/typescript-language-features/src/utils/fileSchemes.ts +++ b/extensions/typescript-language-features/src/utils/fileSchemes.ts @@ -6,9 +6,19 @@ export const file = 'file'; export const untitled = 'untitled'; export const git = 'git'; +/** Live share scheme */ +export const vsls = 'vsls'; export const walkThroughSnippet = 'walkThroughSnippet'; export const semanticSupportedSchemes = [ file, untitled, ]; + +/** + * File scheme for which JS/TS language feature should be disabled + */ +export const disabledSchemes = new Set([ + git, + vsls +]); diff --git a/extensions/typescript-language-features/src/utils/snippetForFunctionCall.ts b/extensions/typescript-language-features/src/utils/snippetForFunctionCall.ts index 6faf19eff48..e0185db581b 100644 --- a/extensions/typescript-language-features/src/utils/snippetForFunctionCall.ts +++ b/extensions/typescript-language-features/src/utils/snippetForFunctionCall.ts @@ -73,7 +73,9 @@ function getParameterListParts( const next = displayParts[i + 1]; // Skip optional parameters const nameIsFollowedByOptionalIndicator = next && next.text === '?'; - if (!nameIsFollowedByOptionalIndicator) { + // Skip this parameter + const nameIsThis = part.text === 'this'; + if (!nameIsFollowedByOptionalIndicator && !nameIsThis) { parts.push(part); } hasOptionalParameters = hasOptionalParameters || nameIsFollowedByOptionalIndicator; diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/index.ts b/extensions/vscode-api-tests/src/singlefolder-tests/index.ts index 8379f9b1ab7..3bd54c52ef6 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/index.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/index.ts @@ -20,7 +20,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 8b2f8c057e0..8e2afa3ba13 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget, Disposable, UIKind, env, EnvironmentVariableMutatorType, EnvironmentVariableMutator, extensions, ExtensionContext } from 'vscode'; +import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget, Disposable, UIKind, env, EnvironmentVariableMutatorType, EnvironmentVariableMutator, extensions, ExtensionContext, TerminalOptions, ExtensionTerminalOptions } from 'vscode'; import { doesNotThrow, equal, ok, deepEqual, throws } from 'assert'; // Disable terminal tests: @@ -168,8 +168,10 @@ import { doesNotThrow, equal, ok, deepEqual, throws } from 'assert'; const terminal = window.createTerminal(options); try { equal(terminal.name, 'foo'); - deepEqual(terminal.creationOptions, options); - throws(() => (terminal.creationOptions).name = 'bad', 'creationOptions should be readonly at runtime'); + const terminalOptions = terminal.creationOptions as TerminalOptions; + equal(terminalOptions.name, 'foo'); + equal(terminalOptions.hideFromUser, true); + throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); } catch (e) { done(e); return; @@ -460,10 +462,6 @@ import { doesNotThrow, equal, ok, deepEqual, throws } from 'assert'; } term.show(); disposables.push(window.onDidChangeTerminalDimensions(e => { - if (e.dimensions.columns === 0 || e.dimensions.rows === 0) { - // HACK: Ignore the event if dimension(s) are zero (#83778) - return; - } // The default pty dimensions have a chance to appear here since override // dimensions happens after the terminal is created. If so just ignore and // wait for the right dimensions @@ -609,8 +607,10 @@ import { doesNotThrow, equal, ok, deepEqual, throws } from 'assert'; const terminal = window.createTerminal(options); try { equal(terminal.name, 'foo'); - deepEqual(terminal.creationOptions, options); - throws(() => (terminal.creationOptions).name = 'bad', 'creationOptions should be readonly at runtime'); + const terminalOptions = terminal.creationOptions as ExtensionTerminalOptions; + equal(terminalOptions.name, 'foo'); + equal(terminalOptions.pty, pty); + throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); } catch (e) { done(e); } diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts index 6177c155b52..fd97ea91728 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts @@ -17,7 +17,7 @@ function workspaceFile(...segments: string[]) { const testDocument = workspaceFile('bower.json'); -suite('vscode API - webview', () => { +suite.skip('vscode API - webview', () => { const disposables: vscode.Disposable[] = []; function _register(disposable: T) { @@ -86,7 +86,7 @@ suite('vscode API - webview', () => { } }); - test('webviews should preserve vscode API state when they are hidden', async () => { + test.skip('webviews should preserve vscode API state when they are hidden', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true })); const ready = getMesssage(webview); webview.webview.html = createHtmlDocumentWithBody(/*html*/` @@ -239,7 +239,7 @@ suite('vscode API - webview', () => { }); - test('webviews should only be able to load resources from workspace by default', async () => { + test.skip('webviews should only be able to load resources from workspace by default', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { @@ -272,6 +272,18 @@ suite('vscode API - webview', () => { const response = await sendRecieveMessage(webview, { src: imagePath.toString() }); assert.strictEqual(response.value, true); } + // { + // // #102188. Resource filename containing special characters like '%', '#', '?'. + // const imagePath = webview.webview.asWebviewUri(workspaceFile('image%02.png')); + // const response = await sendRecieveMessage(webview, { src: imagePath.toString() }); + // assert.strictEqual(response.value, true); + // } + // { + // // #102188. Resource filename containing special characters like '%', '#', '?'. + // const imagePath = webview.webview.asWebviewUri(workspaceFile('image%.png')); + // const response = await sendRecieveMessage(webview, { src: imagePath.toString() }); + // assert.strictEqual(response.value, true); + // } { const imagePath = webview.webview.asWebviewUri(workspaceFile('no-such-image.png')); const response = await sendRecieveMessage(webview, { src: imagePath.toString() }); @@ -284,7 +296,7 @@ suite('vscode API - webview', () => { } }); - test('webviews should allow overriding allowed resource paths using localResourceRoots', async () => { + test.skip('webviews should allow overriding allowed resource paths using localResourceRoots', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, localResourceRoots: [workspaceFile('sub')] @@ -312,7 +324,7 @@ suite('vscode API - webview', () => { } }); - test('webviews using hard-coded old style vscode-resource uri should work', async () => { + test.skip('webviews using hard-coded old style vscode-resource uri should work', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, localResourceRoots: [workspaceFile('sub')] diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts index 4ec107c23be..53acdcf23dc 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -167,57 +167,47 @@ import { window, tasks, Disposable, TaskDefinition, Task, EventEmitter, CustomEx commands.executeCommand('workbench.action.tasks.runTask', `${taskType}: ${taskName}`); }); - test('Execution from onDidEndTaskProcess is equal to original', () => { - return new Promise(async (resolve, reject) => { + test('Execution from onDidEndTaskProcess and onDidStartTaskProcess are equal to original', () => { + return new Promise(async (resolve) => { const task = new Task({ type: 'testTask' }, TaskScope.Workspace, 'echo', 'testTask', new ShellExecution('echo', ['hello test'])); let taskExecution: TaskExecution | undefined; - - disposables.push(tasks.onDidStartTaskProcess(e => { - if (taskExecution === undefined) { - reject('taskExecution is still undefined when process started.'); - } else if (e.execution !== taskExecution) { - reject('Unexpected task execution value in start process.'); + const executeDoneEvent: EventEmitter = new EventEmitter(); + const taskExecutionShouldBeSet: Promise = new Promise(resolve => { + const disposable = executeDoneEvent.event(() => { + resolve(); + disposable.dispose(); + }); + }); + let count = 2; + const progressMade: EventEmitter = new EventEmitter(); + let startSucceeded = false; + let endSucceeded = false; + disposables.push(progressMade.event(() => { + count--; + if ((count === 0) && startSucceeded && endSucceeded) { + resolve(); } })); - disposables.push(tasks.onDidEndTaskProcess(e => { - if (taskExecution === undefined) { - reject('taskExecution is still undefined when process ended.'); - } else if (e.execution === taskExecution) { - resolve(); - } else { - reject('Unexpected task execution value in end process.'); - } - })); - - taskExecution = await tasks.executeTask(task); - }); - }); - - test('Execution from onDidStartTaskProcess is equal to original', () => { - return new Promise(async (resolve, reject) => { - const task = new Task({ type: 'testTask' }, TaskScope.Workspace, 'echo', 'testTask', new ShellExecution('echo', ['hello test'])); - let taskExecution: TaskExecution | undefined; - - disposables.push(tasks.onDidStartTaskProcess(e => { - if (taskExecution === undefined) { - reject('taskExecution is still undefined when process started.'); - } else if (e.execution === taskExecution) { - resolve(); - } else { - reject('Unexpected task execution value in start process.'); - } - })); - - disposables.push(tasks.onDidEndTaskProcess(e => { - if (taskExecution === undefined) { - reject('taskExecution is still undefined when process ended.'); - } else if (e.execution !== taskExecution) { - reject('Unexpected task execution value in end process.'); + + disposables.push(tasks.onDidStartTaskProcess(async (e) => { + await taskExecutionShouldBeSet; + if (e.execution === taskExecution) { + startSucceeded = true; + progressMade.fire(); + } + })); + + disposables.push(tasks.onDidEndTaskProcess(async (e) => { + await taskExecutionShouldBeSet; + if (e.execution === taskExecution) { + endSucceeded = true; + progressMade.fire(); } })); taskExecution = await tasks.executeTask(task); + executeDoneEvent.fire(); }); }); @@ -228,8 +218,10 @@ import { window, tasks, Disposable, TaskDefinition, Task, EventEmitter, CustomEx private readonly writeEmitter = new EventEmitter(); public readonly onDidWrite: Event = this.writeEmitter.event; public async close(): Promise { } + private closeEmitter = new EventEmitter(); + onDidClose: Event = this.closeEmitter.event; public open(): void { - this.close(); + this.closeEmitter.fire(); resolve(); } } diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index 3949c1d1727..6e1034001f4 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -551,7 +551,7 @@ suite('vscode API - workspace', () => { }); test('findFiles', () => { - return vscode.workspace.findFiles('**/*.png').then((res) => { + return vscode.workspace.findFiles('**/image.png').then((res) => { assert.equal(res.length, 2); assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); }); @@ -572,14 +572,14 @@ suite('vscode API - workspace', () => { }); test('findFiles - exclude', () => { - return vscode.workspace.findFiles('**/*.png').then((res) => { + return vscode.workspace.findFiles('**/image.png').then((res) => { assert.equal(res.length, 2); assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); }); }); test('findFiles, exclude', () => { - return vscode.workspace.findFiles('**/*.png', '**/sub/**').then((res) => { + return vscode.workspace.findFiles('**/image.png', '**/sub/**').then((res) => { assert.equal(res.length, 1); assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); }); diff --git a/extensions/vscode-api-tests/src/workspace-tests/index.ts b/extensions/vscode-api-tests/src/workspace-tests/index.ts index dfef493b2ab..7f032ab0b5e 100644 --- a/extensions/vscode-api-tests/src/workspace-tests/index.ts +++ b/extensions/vscode-api-tests/src/workspace-tests/index.ts @@ -20,7 +20,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/vscode-api-tests/testWorkspace/image%.png b/extensions/vscode-api-tests/testWorkspace/image%.png new file mode 100644 index 00000000000..15b462975be Binary files /dev/null and b/extensions/vscode-api-tests/testWorkspace/image%.png differ diff --git a/extensions/vscode-api-tests/testWorkspace/image%02.png b/extensions/vscode-api-tests/testWorkspace/image%02.png new file mode 100644 index 00000000000..15b462975be Binary files /dev/null and b/extensions/vscode-api-tests/testWorkspace/image%02.png differ diff --git a/extensions/vscode-colorize-tests/src/index.ts b/extensions/vscode-colorize-tests/src/index.ts index a315ee36112..691ba5c6f07 100644 --- a/extensions/vscode-colorize-tests/src/index.ts +++ b/extensions/vscode-colorize-tests/src/index.ts @@ -20,7 +20,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/vscode-custom-editor-tests/customEditorMedia/textEditor.js b/extensions/vscode-custom-editor-tests/customEditorMedia/textEditor.js new file mode 100644 index 00000000000..8978b201c9f --- /dev/null +++ b/extensions/vscode-custom-editor-tests/customEditorMedia/textEditor.js @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// @ts-check +(function () { + // @ts-ignore + const vscode = acquireVsCodeApi(); + + const textArea = document.querySelector('textarea'); + + const initialState = vscode.getState(); + if (initialState) { + textArea.value = initialState.value; + } + + window.addEventListener('message', e => { + switch (e.data.type) { + case 'fakeInput': + { + const value = e.data.value; + textArea.value = value; + onInput(); + break; + } + + case 'setValue': + { + const value = e.data.value; + textArea.value = value; + vscode.setState({ value }); + + vscode.postMessage({ + type: 'didChangeContent', + value: value + }); + break; + } + } + }); + + const onInput = () => { + const value = textArea.value; + vscode.setState({ value }); + vscode.postMessage({ + type: 'edit', + value: value + }); + vscode.postMessage({ + type: 'didChangeContent', + value: value + }); + }; + + textArea.addEventListener('input', onInput); +}()); diff --git a/extensions/vscode-custom-editor-tests/package.json b/extensions/vscode-custom-editor-tests/package.json new file mode 100644 index 00000000000..08b6702b80a --- /dev/null +++ b/extensions/vscode-custom-editor-tests/package.json @@ -0,0 +1,44 @@ +{ + "name": "vscode-custom-editor-tests", + "description": "Custom editor tests for VS Code", + "version": "0.0.1", + "publisher": "vscode", + "license": "MIT", + "private": true, + "activationEvents": [ + "onCustomEditor:testWebviewEditor.abc" + ], + "main": "./out/extension", + "enableProposedApi": true, + "engines": { + "vscode": "^1.48.0" + }, + "scripts": { + "compile": "node ./node_modules/vscode/bin/compile -watch -p ./", + "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-notebook-tests ./tsconfig.json" + }, + "dependencies": { + "p-limit": "^3.0.2" + }, + "devDependencies": { + "@types/node": "^12.11.7", + "@types/p-limit": "^2.2.0", + "mocha": "^2.3.3", + "mocha-junit-reporter": "^1.17.0", + "mocha-multi-reporters": "^1.1.7", + "vscode": "^1.1.36" + }, + "contributes": { + "customEditors": [ + { + "viewType": "testWebviewEditor.abc", + "displayName": "Test ABC editor", + "selector": [ + { + "filenamePattern": "*.abc" + } + ] + } + ] + } +} diff --git a/extensions/vscode-custom-editor-tests/src/customTextEditor.ts b/extensions/vscode-custom-editor-tests/src/customTextEditor.ts new file mode 100644 index 00000000000..cced14b9401 --- /dev/null +++ b/extensions/vscode-custom-editor-tests/src/customTextEditor.ts @@ -0,0 +1,165 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as pLimit from 'p-limit'; +import * as path from 'path'; +import * as vscode from 'vscode'; +import { Disposable } from './dispose'; + +export namespace Testing { + export const abcEditorContentChangeCommand = '_abcEditor.contentChange'; + export const abcEditorTypeCommand = '_abcEditor.type'; + + export interface CustomEditorContentChangeEvent { + readonly content: string; + readonly source: vscode.Uri; + } +} + +export class AbcTextEditorProvider implements vscode.CustomTextEditorProvider { + + public static readonly viewType = 'testWebviewEditor.abc'; + + private activeEditor?: AbcEditor; + + public constructor( + private readonly context: vscode.ExtensionContext, + ) { } + + public register(): vscode.Disposable { + const provider = vscode.window.registerCustomEditorProvider(AbcTextEditorProvider.viewType, this); + + const commands: vscode.Disposable[] = []; + commands.push(vscode.commands.registerCommand(Testing.abcEditorTypeCommand, (content: string) => { + this.activeEditor?.testing_fakeInput(content); + })); + + return vscode.Disposable.from(provider, ...commands); + } + + public async resolveCustomTextEditor(document: vscode.TextDocument, panel: vscode.WebviewPanel) { + const editor = new AbcEditor(document, this.context.extensionPath, panel); + + this.activeEditor = editor; + + panel.onDidChangeViewState(({ webviewPanel }) => { + if (this.activeEditor === editor && !webviewPanel.active) { + this.activeEditor = undefined; + } + if (webviewPanel.active) { + this.activeEditor = editor; + } + }); + } +} + +class AbcEditor extends Disposable { + + public readonly _onDispose = this._register(new vscode.EventEmitter()); + public readonly onDispose = this._onDispose.event; + + private readonly limit = pLimit(1); + private syncedVersion: number = -1; + private currentWorkspaceEdit?: Thenable; + + constructor( + private readonly document: vscode.TextDocument, + private readonly _extensionPath: string, + private readonly panel: vscode.WebviewPanel, + ) { + super(); + + panel.webview.options = { + enableScripts: true, + }; + panel.webview.html = this.html; + + this._register(vscode.workspace.onDidChangeTextDocument(e => { + if (e.document === this.document) { + this.update(); + } + })); + + this._register(panel.webview.onDidReceiveMessage(message => { + switch (message.type) { + case 'edit': + this.doEdit(message.value); + break; + + case 'didChangeContent': + vscode.commands.executeCommand(Testing.abcEditorContentChangeCommand, { + content: message.value, + source: document.uri, + } as Testing.CustomEditorContentChangeEvent); + break; + } + })); + + this._register(panel.onDidDispose(() => { this.dispose(); })); + + this.update(); + } + + public testing_fakeInput(value: string) { + this.panel.webview.postMessage({ + type: 'fakeInput', + value: value, + }); + } + + private async doEdit(value: string) { + const edit = new vscode.WorkspaceEdit(); + edit.replace(this.document.uri, this.document.validateRange(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(999999, 999999))), value); + this.limit(() => { + this.currentWorkspaceEdit = vscode.workspace.applyEdit(edit).then(() => { + this.syncedVersion = this.document.version; + this.currentWorkspaceEdit = undefined; + }); + return this.currentWorkspaceEdit; + }); + } + + public dispose() { + if (this.isDisposed) { + return; + } + + this._onDispose.fire(); + super.dispose(); + } + + private get html() { + const contentRoot = path.join(this._extensionPath, 'customEditorMedia'); + const scriptUri = vscode.Uri.file(path.join(contentRoot, 'textEditor.js')); + const nonce = Date.now() + ''; + return /* html */` + + + + + + Document + + + + + + `; + } + + public async update() { + await this.currentWorkspaceEdit; + + if (this.isDisposed || this.syncedVersion >= this.document.version) { + return; + } + + this.panel.webview.postMessage({ + type: 'setValue', + value: this.document.getText(), + }); + this.syncedVersion = this.document.version; + } +} diff --git a/extensions/vscode-custom-editor-tests/src/dispose.ts b/extensions/vscode-custom-editor-tests/src/dispose.ts new file mode 100644 index 00000000000..548094c28e5 --- /dev/null +++ b/extensions/vscode-custom-editor-tests/src/dispose.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +export function disposeAll(disposables: vscode.Disposable[]) { + while (disposables.length) { + const item = disposables.pop(); + if (item) { + item.dispose(); + } + } +} + +export abstract class Disposable { + private _isDisposed = false; + + protected _disposables: vscode.Disposable[] = []; + + public dispose(): any { + if (this._isDisposed) { + return; + } + this._isDisposed = true; + disposeAll(this._disposables); + } + + protected _register(value: T): T { + if (this._isDisposed) { + value.dispose(); + } else { + this._disposables.push(value); + } + return value; + } + + protected get isDisposed() { + return this._isDisposed; + } +} \ No newline at end of file diff --git a/extensions/github-browser/extension.webpack.config.js b/extensions/vscode-custom-editor-tests/src/extension.ts similarity index 60% rename from extensions/github-browser/extension.webpack.config.js rename to extensions/vscode-custom-editor-tests/src/extension.ts index 45600607fc5..0a83f97fce2 100644 --- a/extensions/github-browser/extension.webpack.config.js +++ b/extensions/vscode-custom-editor-tests/src/extension.ts @@ -3,15 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -//@ts-check +import * as vscode from 'vscode'; +import { AbcTextEditorProvider } from './customTextEditor'; -'use strict'; - -const withDefaults = require('../shared.webpack.config'); - -module.exports = withDefaults({ - context: __dirname, - entry: { - extension: './src/extension.ts' - } -}); +export function activate(context: vscode.ExtensionContext) { + context.subscriptions.push(new AbcTextEditorProvider(context).register()); +} diff --git a/extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts b/extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts new file mode 100644 index 00000000000..d66ab665b8e --- /dev/null +++ b/extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts @@ -0,0 +1,314 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as vscode from 'vscode'; +import { Testing } from '../customTextEditor'; +import { closeAllEditors, delay, disposeAll, randomFilePath } from './utils'; + +assert.ok(vscode.workspace.rootPath); +const testWorkspaceRoot = vscode.Uri.file(path.join(vscode.workspace.rootPath!, 'customEditors')); + +const commands = Object.freeze({ + open: 'vscode.open', + openWith: 'vscode.openWith', + save: 'workbench.action.files.save', + undo: 'undo', +}); + +async function writeRandomFile(options: { ext: string; contents: string; }): Promise { + const fakeFile = randomFilePath({ root: testWorkspaceRoot, ext: options.ext }); + await fs.promises.writeFile(fakeFile.fsPath, Buffer.from(options.contents)); + return fakeFile; +} + +const disposables: vscode.Disposable[] = []; +function _register(disposable: T) { + disposables.push(disposable); + return disposable; +} + +class CustomEditorUpdateListener { + + public static create() { + return _register(new CustomEditorUpdateListener()); + } + + private readonly commandSubscription: vscode.Disposable; + + private readonly unconsumedResponses: Array = []; + private readonly callbackQueue: Array<(data: Testing.CustomEditorContentChangeEvent) => void> = []; + + private constructor() { + this.commandSubscription = vscode.commands.registerCommand(Testing.abcEditorContentChangeCommand, (data: Testing.CustomEditorContentChangeEvent) => { + if (this.callbackQueue.length) { + const callback = this.callbackQueue.shift(); + assert.ok(callback); + callback!(data); + } else { + this.unconsumedResponses.push(data); + } + }); + } + + dispose() { + this.commandSubscription.dispose(); + } + + async nextResponse(): Promise { + if (this.unconsumedResponses.length) { + return this.unconsumedResponses.shift()!; + } + + return new Promise(resolve => { + this.callbackQueue.push(resolve); + }); + } +} + + +suite('CustomEditor tests', () => { + setup(async () => { + await closeAllEditors(); + await resetTestWorkspace(); + }); + + teardown(async () => { + await closeAllEditors(); + disposeAll(disposables); + await resetTestWorkspace(); + }); + + test('Should load basic content from disk', async () => { + const startingContent = `load, init`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + await vscode.commands.executeCommand(commands.open, testDocument); + + const { content } = await listener.nextResponse(); + assert.equal(content, startingContent); + }); + + test('Should support basic edits', async () => { + const startingContent = `basic edit, init`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + await vscode.commands.executeCommand(commands.open, testDocument); + await listener.nextResponse(); + + const newContent = `basic edit test`; + await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, newContent); + const { content } = await listener.nextResponse(); + assert.equal(content, newContent); + }); + + test('Should support single undo', async () => { + const startingContent = `single undo, init`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + await vscode.commands.executeCommand(commands.open, testDocument); + await listener.nextResponse(); + + const newContent = `undo test`; + { + await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, newContent); + const { content } = await listener.nextResponse(); + assert.equal(content, newContent); + } + await delay(100); + { + await vscode.commands.executeCommand(commands.undo); + const { content } = await listener.nextResponse(); + assert.equal(content, startingContent); + } + }); + + test('Should support multiple undo', async () => { + const startingContent = `multiple undo, init`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + await vscode.commands.executeCommand(commands.open, testDocument); + await listener.nextResponse(); + + const count = 10; + + // Make edits + for (let i = 0; i < count; ++i) { + await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, `${i}`); + const { content } = await listener.nextResponse(); + assert.equal(`${i}`, content); + } + + // Then undo them in order + for (let i = count - 1; i; --i) { + await delay(100); + await vscode.commands.executeCommand(commands.undo); + const { content } = await listener.nextResponse(); + assert.equal(`${i - 1}`, content); + } + + { + await delay(100); + await vscode.commands.executeCommand(commands.undo); + const { content } = await listener.nextResponse(); + assert.equal(content, startingContent); + } + }); + + test('Should update custom editor on file move', async () => { + const startingContent = `file move, init`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + await vscode.commands.executeCommand(commands.open, testDocument); + await listener.nextResponse(); + + const newFileName = vscode.Uri.file(path.join(testWorkspaceRoot.fsPath, 'y.abc')); + + const edit = new vscode.WorkspaceEdit(); + edit.renameFile(testDocument, newFileName); + + await vscode.workspace.applyEdit(edit); + + const response = (await listener.nextResponse()); + assert.equal(response.content, startingContent); + assert.equal(response.source.toString(), newFileName.toString()); + }); + + test('Should support saving custom editors', async () => { + const startingContent = `save, init`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + await vscode.commands.executeCommand(commands.open, testDocument); + await listener.nextResponse(); + + const newContent = `save, new`; + { + await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, newContent); + const { content } = await listener.nextResponse(); + assert.equal(content, newContent); + } + { + await vscode.commands.executeCommand(commands.save); + const fileContent = (await fs.promises.readFile(testDocument.fsPath)).toString(); + assert.equal(fileContent, newContent); + } + }); + + test('Should undo after saving custom editor', async () => { + const startingContent = `undo after save, init`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + await vscode.commands.executeCommand(commands.open, testDocument); + await listener.nextResponse(); + + const newContent = `undo after save, new`; + { + await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, newContent); + const { content } = await listener.nextResponse(); + assert.equal(content, newContent); + } + { + await vscode.commands.executeCommand(commands.save); + const fileContent = (await fs.promises.readFile(testDocument.fsPath)).toString(); + assert.equal(fileContent, newContent); + } + await delay(100); + { + await vscode.commands.executeCommand(commands.undo); + const { content } = await listener.nextResponse(); + assert.equal(content, startingContent); + } + }); + + test.skip('Should support untitled custom editors', async () => { + const listener = CustomEditorUpdateListener.create(); + + const untitledFile = randomFilePath({ root: testWorkspaceRoot, ext: '.abc' }).with({ scheme: 'untitled' }); + + await vscode.commands.executeCommand(commands.open, untitledFile); + assert.equal((await listener.nextResponse()).content, ''); + + await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, `123`); + assert.equal((await listener.nextResponse()).content, '123'); + + await vscode.commands.executeCommand(commands.save); + const content = await fs.promises.readFile(untitledFile.fsPath); + assert.equal(content.toString(), '123'); + }); + + test.skip('When switching away from a non-default custom editors and then back, we should continue using the non-default editor', async () => { + const startingContent = `switch, init`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + { + await vscode.commands.executeCommand(commands.open, testDocument, { preview: false }); + const { content } = await listener.nextResponse(); + assert.strictEqual(content, startingContent.toString()); + assert.ok(!vscode.window.activeTextEditor); + } + + // Switch to non-default editor + await vscode.commands.executeCommand(commands.openWith, testDocument, 'default', { preview: false }); + assert.strictEqual(vscode.window.activeTextEditor!?.document.uri.toString(), testDocument.toString()); + + // Then open a new document (hiding existing one) + const otherFile = vscode.Uri.file(path.join(testWorkspaceRoot.fsPath, 'other.json')); + await vscode.commands.executeCommand(commands.open, otherFile); + assert.strictEqual(vscode.window.activeTextEditor!?.document.uri.toString(), otherFile.toString()); + + // And then back + await vscode.commands.executeCommand('workbench.action.navigateBack'); + await vscode.commands.executeCommand('workbench.action.navigateBack'); + + // Make sure we have the file on as text + assert.ok(vscode.window.activeTextEditor); + assert.strictEqual(vscode.window.activeTextEditor!?.document.uri.toString(), testDocument.toString()); + }); + + test('Should release the text document when the editor is closed', async () => { + const startingContent = `release document init,`; + const testDocument = await writeRandomFile({ ext: '.abc', contents: startingContent }); + + const listener = CustomEditorUpdateListener.create(); + + await vscode.commands.executeCommand(commands.open, testDocument); + await listener.nextResponse(); + + const doc = vscode.workspace.textDocuments.find(x => x.uri.toString() === testDocument.toString()); + assert.ok(doc); + assert.ok(!doc!.isClosed); + + await closeAllEditors(); + await delay(100); + assert.ok(doc!.isClosed); + }); +}); + +async function resetTestWorkspace() { + try { + await vscode.workspace.fs.delete(testWorkspaceRoot, { recursive: true }); + } catch { + // ok if file doesn't exist + } + await vscode.workspace.fs.createDirectory(testWorkspaceRoot); +} diff --git a/extensions/vscode-custom-editor-tests/src/test/index.ts b/extensions/vscode-custom-editor-tests/src/test/index.ts new file mode 100644 index 00000000000..a60622b2f28 --- /dev/null +++ b/extensions/vscode-custom-editor-tests/src/test/index.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const path = require('path'); +const testRunner = require('vscode/lib/testrunner'); + +const suite = 'Custom Editor Tests'; + +const options: any = { + ui: 'tdd', + useColors: (!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY && process.platform !== 'win32'), + timeout: 6000000 +}; + +if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { + options.reporter = 'mocha-multi-reporters'; + options.reporterOptions = { + reporterEnabled: 'spec, mocha-junit-reporter', + mochaJunitReporterReporterOptions: { + testsuitesTitle: `${suite} ${process.platform}`, + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + } + }; +} + +testRunner.configure(options); + +export = testRunner; diff --git a/extensions/vscode-custom-editor-tests/src/test/utils.ts b/extensions/vscode-custom-editor-tests/src/test/utils.ts new file mode 100644 index 00000000000..5edd53b27cc --- /dev/null +++ b/extensions/vscode-custom-editor-tests/src/test/utils.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +export function randomFilePath(args: { root: vscode.Uri, ext: string }): vscode.Uri { + const fileName = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10); + return (vscode.Uri as any).joinPath(args.root, fileName + args.ext); +} + +export function closeAllEditors(): Thenable { + return vscode.commands.executeCommand('workbench.action.closeAllEditors'); +} + +export function disposeAll(disposables: vscode.Disposable[]) { + vscode.Disposable.from(...disposables).dispose(); +} + +export function delay(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/extensions/vscode-web-playground/src/typings/ref.d.ts b/extensions/vscode-custom-editor-tests/src/typings/ref.d.ts similarity index 71% rename from extensions/vscode-web-playground/src/typings/ref.d.ts rename to extensions/vscode-custom-editor-tests/src/typings/ref.d.ts index 9abc416f7e8..bf67b19225d 100644 --- a/extensions/vscode-web-playground/src/typings/ref.d.ts +++ b/extensions/vscode-custom-editor-tests/src/typings/ref.d.ts @@ -4,7 +4,5 @@ *--------------------------------------------------------------------------------------------*/ /// -/// -/// -/// /// + diff --git a/extensions/github-browser/tsconfig.json b/extensions/vscode-custom-editor-tests/tsconfig.json similarity index 61% rename from extensions/github-browser/tsconfig.json rename to extensions/vscode-custom-editor-tests/tsconfig.json index eb413a12602..296ddb38fcb 100644 --- a/extensions/github-browser/tsconfig.json +++ b/extensions/vscode-custom-editor-tests/tsconfig.json @@ -1,14 +1,9 @@ { "extends": "../shared.tsconfig.json", "compilerOptions": { - "experimentalDecorators": true, - "lib": [ - "es2018", - "dom" - ], "outDir": "./out" }, "include": [ "src/**/*" ] -} +} \ No newline at end of file diff --git a/extensions/vscode-custom-editor-tests/yarn.lock b/extensions/vscode-custom-editor-tests/yarn.lock new file mode 100644 index 00000000000..0d39ebbaa5e --- /dev/null +++ b/extensions/vscode-custom-editor-tests/yarn.lock @@ -0,0 +1,507 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/node@^12.11.7": + version "12.12.53" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.53.tgz#be0d375933c3d15ef2380dafb3b0350ea7021129" + integrity sha512-51MYTDTyCziHb70wtGNFRwB4l+5JNvdqzFSkbDvpbftEgVUBEE+T5f7pROhWMp/fxp07oNIEQZd5bbfAH22ohQ== + +"@types/p-limit@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/p-limit/-/p-limit-2.2.0.tgz#94a608e9b258a6c6156a13d1a14fd720dba70b97" + integrity sha512-fGFbybl1r0oE9mqgfc2EHHUin9ZL5rbQIexWI6jYRU1ADVn4I3LHzT+g/kpPpZsfp8PB94CQ655pfAjNF8LP6A== + dependencies: + p-limit "*" + +agent-base@4, agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +agent-base@6: + version "6.0.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.1.tgz#808007e4e5867decb0ab6ab2f928fbdb5a596db4" + integrity sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg== + dependencies: + debug "4" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +charenc@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + +commander@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + integrity sha1-+mihT2qUXVTbvlDYzbMyDp47GgY= + +commander@2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== + +commander@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +crypt@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + +debug@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + integrity sha1-+HBX6ZWxofauaklgZkE3vFbwOdo= + dependencies: + ms "0.7.1" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +diff@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + integrity sha1-fyjS657nsVqX79ic5j3P2qPMur8= + +diff@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +escape-string-regexp@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + integrity sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE= + +escape-string-regexp@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +glob@3.2.11: + version "3.2.11" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" + integrity sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0= + dependencies: + inherits "2" + minimatch "0.3" + +glob@7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +growl@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" + integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +https-proxy-agent@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-buffer@~1.1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +jade@0.26.3: + version "0.26.3" + resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + integrity sha1-jxDXl32NefL2/4YqgbBRPMslaGw= + dependencies: + commander "0.6.1" + mkdirp "0.3.0" + +lodash@^4.16.4: + version "4.17.19" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" + integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= + +md5@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" + integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= + dependencies: + charenc "~0.0.1" + crypt "~0.0.1" + is-buffer "~1.1.1" + +minimatch@0.3: + version "0.3.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" + integrity sha1-J12O2qxPG7MyZHIInnlJyDlGmd0= + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4= + +mkdirp@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mocha-junit-reporter@^1.17.0: + version "1.23.3" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.3.tgz#941e219dd759ed732f8641e165918aa8b167c981" + integrity sha512-ed8LqbRj1RxZfjt/oC9t12sfrWsjZ3gNnbhV1nuj9R/Jb5/P3Xb4duv2eCfCDMYH+fEu0mqca7m4wsiVjsxsvA== + dependencies: + debug "^2.2.0" + md5 "^2.1.0" + mkdirp "~0.5.1" + strip-ansi "^4.0.0" + xml "^1.0.0" + +mocha-multi-reporters@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz#cc7f3f4d32f478520941d852abb64d9988587d82" + integrity sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI= + dependencies: + debug "^3.1.0" + lodash "^4.16.4" + +mocha@^2.3.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" + integrity sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg= + dependencies: + commander "2.3.0" + debug "2.2.0" + diff "1.4.0" + escape-string-regexp "1.0.2" + glob "3.2.11" + growl "1.9.2" + jade "0.26.3" + mkdirp "0.5.1" + supports-color "1.2.0" + to-iso-string "0.0.2" + +mocha@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" + integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== + dependencies: + browser-stdout "1.3.1" + commander "2.15.1" + debug "3.1.0" + diff "3.5.0" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.5" + he "1.1.1" + minimatch "3.0.4" + mkdirp "0.5.1" + supports-color "5.4.0" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + integrity sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg= + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +p-limit@*, p-limit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.0.2.tgz#1664e010af3cadc681baafd3e2a437be7b0fb5fe" + integrity sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg== + dependencies: + p-try "^2.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +semver@^5.4.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= + +source-map-support@^0.5.0: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +supports-color@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + integrity sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4= + +supports-color@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== + dependencies: + has-flag "^3.0.0" + +to-iso-string@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" + integrity sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE= + +vscode-test@^0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/vscode-test/-/vscode-test-0.4.3.tgz#461ebf25fc4bc93d77d982aed556658a2e2b90b8" + integrity sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w== + dependencies: + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + +vscode@^1.1.36: + version "1.1.37" + resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.37.tgz#c2a770bee4bb3fff765e2b72c7bcc813b8a6bb0a" + integrity sha512-vJNj6IlN7IJPdMavlQa1KoFB3Ihn06q1AiN3ZFI/HfzPNzbKZWPPuiU+XkpNOfGU5k15m4r80nxNPlM7wcc0wg== + dependencies: + glob "^7.1.2" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + mocha "^5.2.0" + semver "^5.4.1" + source-map-support "^0.5.0" + vscode-test "^0.4.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +xml@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= diff --git a/extensions/vscode-notebook-tests/src/index.ts b/extensions/vscode-notebook-tests/src/index.ts index 2125e68c3d8..2da40bed655 100644 --- a/extensions/vscode-notebook-tests/src/index.ts +++ b/extensions/vscode-notebook-tests/src/index.ts @@ -20,7 +20,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { reporterEnabled: 'spec, mocha-junit-reporter', mochaJunitReporterReporterOptions: { testsuitesTitle: `${suite} ${process.platform}`, - mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } diff --git a/extensions/vscode-notebook-tests/src/notebook.test.ts b/extensions/vscode-notebook-tests/src/notebook.test.ts index f5c785ca8b2..c09d171fc6d 100644 --- a/extensions/vscode-notebook-tests/src/notebook.test.ts +++ b/extensions/vscode-notebook-tests/src/notebook.test.ts @@ -131,6 +131,46 @@ suite('Notebook API tests', () => { await firstDocumentClose; }); + test('notebook open/close, all cell-documents are ready', async function () { + const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + + const p = getEventOncePromise(vscode.notebook.onDidOpenNotebookDocument).then(notebook => { + for (let cell of notebook.cells) { + const doc = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === cell.uri.toString()); + assert.ok(doc); + assert.strictEqual(doc === cell.document, true); + assert.strictEqual(doc?.languageId, cell.language); + assert.strictEqual(doc?.isDirty, false); + assert.strictEqual(doc?.isClosed, false); + } + }); + + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + await p; + await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + }); + + test('notebook open/close, notebook ready when cell-document open event is fired', async function () { + const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + let didHappen = false; + const p = getEventOncePromise(vscode.workspace.onDidOpenTextDocument).then(doc => { + if (doc.uri.scheme !== 'vscode-notebook-cell') { + return; + } + const notebook = vscode.notebook.notebookDocuments.find(notebook => { + const cell = notebook.cells.find(cell => cell.document === doc); + return Boolean(cell); + }); + assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`); + didHappen = true; + }); + + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + await p; + assert.strictEqual(didHappen, true); + await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + }); + test('shared document in notebook editors', async function () { assertInitalState(); @@ -663,7 +703,7 @@ suite('notebook undo redo', () => { // undo should bring back the deleted cell, and revert to previous content and selection - await vscode.commands.executeCommand('notebook.undo'); + await vscode.commands.executeCommand('undo'); assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 3); assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(vscode.notebook.activeNotebookEditor!.selection!), 1); assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;'); @@ -729,7 +769,7 @@ suite('notebook undo redo', () => { assert.equal(cellOutputsAddedRet.cells[0].outputs.length, 1); const cellOutputClear = getEventOncePromise(vscode.notebook.onDidChangeCellOutputs); - await vscode.commands.executeCommand('notebook.undo'); + await vscode.commands.executeCommand('undo'); const cellOutputsCleardRet = await cellOutputClear; assert.deepEqual(cellOutputsCleardRet, { document: vscode.notebook.activeNotebookEditor!.document, diff --git a/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts b/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts index b129064656e..0cec3fe06d6 100644 --- a/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts +++ b/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts @@ -67,7 +67,7 @@ export function smokeTestActivate(context: vscode.ExtensionContext): any { } })); - context.subscriptions.push(vscode.notebook.registerNotebookKernel('notebookSmokeTest', ['*.vsctestnb'], { + context.subscriptions.push(vscode.notebook.registerNotebookKernel('notebookSmokeTest', ['*.smoke-nb'], { label: 'notebookSmokeTest', executeAllCells: async (_document: vscode.NotebookDocument) => { for (let i = 0; i < _document.cells.length; i++) { diff --git a/extensions/vscode-notebook-tests/src/notebookTestMain.ts b/extensions/vscode-notebook-tests/src/notebookTestMain.ts index d77e0725f5a..c8ea3282c2c 100644 --- a/extensions/vscode-notebook-tests/src/notebookTestMain.ts +++ b/extensions/vscode-notebook-tests/src/notebookTestMain.ts @@ -63,7 +63,7 @@ export function activate(context: vscode.ExtensionContext): any { context.subscriptions.push(vscode.notebook.registerNotebookKernel('notebookKernelTest', ['*.vsctestnb'], { label: 'Notebook Test Kernel', executeAllCells: async (_document: vscode.NotebookDocument) => { - let cell = _document.cells[0]; + const cell = _document.cells[0]; cell.outputs = [{ outputKind: vscode.CellOutputKind.Rich, diff --git a/extensions/vscode-notebook-tests/src/utils.ts b/extensions/vscode-notebook-tests/src/utils.ts index 95dae41d5dc..0a8f20a1942 100644 --- a/extensions/vscode-notebook-tests/src/utils.ts +++ b/extensions/vscode-notebook-tests/src/utils.ts @@ -65,7 +65,7 @@ export class TestFS implements vscode.FileSystemProvider { readDirectory(uri: vscode.Uri): [string, vscode.FileType][] { const entry = this._lookupAsDirectory(uri, false); - let result: [string, vscode.FileType][] = []; + const result: [string, vscode.FileType][] = []; for (const [name, child] of entry.entries) { result.push([name, child.type]); } @@ -83,8 +83,8 @@ export class TestFS implements vscode.FileSystemProvider { } writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void { - let basename = path.posix.basename(uri.path); - let parent = this._lookupParentDirectory(uri); + const basename = path.posix.basename(uri.path); + const parent = this._lookupParentDirectory(uri); let entry = parent.entries.get(basename); if (entry instanceof Directory) { throw vscode.FileSystemError.FileIsADirectory(uri); @@ -115,11 +115,11 @@ export class TestFS implements vscode.FileSystemProvider { throw vscode.FileSystemError.FileExists(newUri); } - let entry = this._lookup(oldUri, false); - let oldParent = this._lookupParentDirectory(oldUri); + const entry = this._lookup(oldUri, false); + const oldParent = this._lookupParentDirectory(oldUri); - let newParent = this._lookupParentDirectory(newUri); - let newName = path.posix.basename(newUri.path); + const newParent = this._lookupParentDirectory(newUri); + const newName = path.posix.basename(newUri.path); oldParent.entries.delete(entry.name); entry.name = newName; @@ -132,9 +132,9 @@ export class TestFS implements vscode.FileSystemProvider { } delete(uri: vscode.Uri): void { - let dirname = uri.with({ path: path.posix.dirname(uri.path) }); - let basename = path.posix.basename(uri.path); - let parent = this._lookupAsDirectory(dirname, false); + const dirname = uri.with({ path: path.posix.dirname(uri.path) }); + const basename = path.posix.basename(uri.path); + const parent = this._lookupAsDirectory(dirname, false); if (!parent.entries.has(basename)) { throw vscode.FileSystemError.FileNotFound(uri); } @@ -145,11 +145,11 @@ export class TestFS implements vscode.FileSystemProvider { } createDirectory(uri: vscode.Uri): void { - let basename = path.posix.basename(uri.path); - let dirname = uri.with({ path: path.posix.dirname(uri.path) }); - let parent = this._lookupAsDirectory(dirname, false); + const basename = path.posix.basename(uri.path); + const dirname = uri.with({ path: path.posix.dirname(uri.path) }); + const parent = this._lookupAsDirectory(dirname, false); - let entry = new Directory(basename); + const entry = new Directory(basename); parent.entries.set(entry.name, entry); parent.mtime = Date.now(); parent.size += 1; @@ -161,7 +161,7 @@ export class TestFS implements vscode.FileSystemProvider { private _lookup(uri: vscode.Uri, silent: false): Entry; private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined; private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined { - let parts = uri.path.split('/'); + const parts = uri.path.split('/'); let entry: Entry = this.root; for (const part of parts) { const partLow = part.toLowerCase(); @@ -173,7 +173,7 @@ export class TestFS implements vscode.FileSystemProvider { if (this.isCaseSensitive) { child = entry.entries.get(part); } else { - for (let [key, value] of entry.entries) { + for (const [key, value] of entry.entries) { if (key.toLowerCase() === partLow) { child = value; break; @@ -194,7 +194,7 @@ export class TestFS implements vscode.FileSystemProvider { } private _lookupAsDirectory(uri: vscode.Uri, silent: boolean): Directory { - let entry = this._lookup(uri, silent); + const entry = this._lookup(uri, silent); if (entry instanceof Directory) { return entry; } @@ -202,7 +202,7 @@ export class TestFS implements vscode.FileSystemProvider { } private _lookupAsFile(uri: vscode.Uri, silent: boolean): File { - let entry = this._lookup(uri, silent); + const entry = this._lookup(uri, silent); if (entry instanceof File) { return entry; } diff --git a/extensions/vscode-web-playground/.gitignore b/extensions/vscode-web-playground/.gitignore deleted file mode 100644 index c19bd94aaa7..00000000000 --- a/extensions/vscode-web-playground/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -dist -out -node_modules diff --git a/extensions/vscode-web-playground/.vscode/tasks.json b/extensions/vscode-web-playground/.vscode/tasks.json deleted file mode 100644 index 390a93a3a7f..00000000000 --- a/extensions/vscode-web-playground/.vscode/tasks.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "2.0.0", - "command": "npm", - "type": "shell", - "presentation": { - "reveal": "silent" - }, - "args": ["run", "compile"], - "isBackground": true, - "problemMatcher": "$tsc-watch" -} diff --git a/extensions/vscode-web-playground/package.json b/extensions/vscode-web-playground/package.json deleted file mode 100644 index 954aec0fae9..00000000000 --- a/extensions/vscode-web-playground/package.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "name": "vscode-web-playground", - "description": "Web playground for VS Code", - "version": "0.0.1", - "publisher": "vscode", - "license": "MIT", - "enableProposedApi": true, - "private": true, - "activationEvents": [ - "onFileSystem:memfs", - "onFileSystem:github", - "onDebug" - ], - "browser": "./dist/browser/extension", - "main": "./out/extension", - "engines": { - "vscode": "^1.25.0" - }, - "contributes": { - "taskDefinitions": [ - { - "type": "custombuildscript", - "required": [ - "flavor" - ], - "properties": { - "flavor": { - "type": "string", - "description": "The build flavor. Should be either '32' or '64'." - }, - "flags": { - "type": "array", - "description": "Additional build flags." - } - } - } - ], - "breakpoints": [ - { - "language": "markdown" - } - ], - "debuggers": [ - { - "type": "mock", - "label": "Mock Debug", - "languages": [ - "markdown" - ], - "configurationAttributes": { - "launch": { - "required": [ - "program" - ], - "properties": { - "program": { - "type": "string", - "description": "Absolute path to a text file.", - "default": "${workspaceFolder}/file.md" - }, - "stopOnEntry": { - "type": "boolean", - "description": "Automatically stop after launch.", - "default": true - }, - "trace": { - "type": "boolean", - "description": "Enable logging of the Debug Adapter Protocol.", - "default": true - } - } - } - }, - "initialConfigurations": [ - { - "type": "mock", - "request": "launch", - "name": "Debug file.md", - "program": "${workspaceFolder}/file.md" - } - ] - } - ], - "resourceLabelFormatters": [ - { - "scheme": "github", - "authority": "*", - "formatting": { - "label": "${authority}${path}", - "separator": "/", - "workspaceSuffix": "GitHub" - } - } - ] - }, - "scripts": { - "compile": "node ./node_modules/vscode/bin/compile -watch -p ./", - "compile-web": "npx webpack-cli --config extension.webpack.config --mode none", - "watch-web": "npx webpack-cli --config extension.webpack.config --mode none --watch --info-verbosity verbose", - "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-web-playground ./tsconfig.json" - }, - "devDependencies": { - "@types/mocha": "2.2.43", - "mocha-junit-reporter": "^1.17.0", - "mocha-multi-reporters": "^1.1.7" - } -} diff --git a/extensions/vscode-web-playground/src/exampleFiles.ts b/extensions/vscode-web-playground/src/exampleFiles.ts deleted file mode 100644 index a385f7b72e7..00000000000 --- a/extensions/vscode-web-playground/src/exampleFiles.ts +++ /dev/null @@ -1,310 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -export const largeTSFile = `/// -/// - -module Mankala { -export var storeHouses = [6,13]; -export var svgNS = 'http://www.w3.org/2000/svg'; - -function createSVGRect(r:Rectangle) { - var rect = document.createElementNS(svgNS,'rect'); - rect.setAttribute('x', r.x.toString()); - rect.setAttribute('y', r.y.toString()); - rect.setAttribute('width', r.width.toString()); - rect.setAttribute('height', r.height.toString()); - return rect; -} - -function createSVGEllipse(r:Rectangle) { - var ell = document.createElementNS(svgNS,'ellipse'); - ell.setAttribute('rx',(r.width/2).toString()); - ell.setAttribute('ry',(r.height/2).toString()); - ell.setAttribute('cx',(r.x+r.width/2).toString()); - ell.setAttribute('cy',(r.y+r.height/2).toString()); - return ell; -} - -function createSVGEllipsePolar(angle:number,radius:number,tx:number,ty:number,cxo:number,cyo:number) { - var ell = document.createElementNS(svgNS,'ellipse'); - ell.setAttribute('rx',radius.toString()); - ell.setAttribute('ry',(radius/3).toString()); - ell.setAttribute('cx',cxo.toString()); - ell.setAttribute('cy',cyo.toString()); - var dangle = angle*(180/Math.PI); - ell.setAttribute('transform','rotate('+dangle+','+cxo+','+cyo+') translate('+tx+','+ty+')'); - return ell; -} - -function createSVGInscribedCircle(sq:Square) { - var circle = document.createElementNS(svgNS,'circle'); - circle.setAttribute('r',(sq.length/2).toString()); - circle.setAttribute('cx',(sq.x+(sq.length/2)).toString()); - circle.setAttribute('cy',(sq.y+(sq.length/2)).toString()); - return circle; -} - -export class Position { - - seedCounts:number[]; - startMove:number; - turn:number; - - constructor(seedCounts:number[],startMove:number,turn:number) { - this.seedCounts = seedCounts; - this.startMove = startMove; - this.turn = turn; - } - - score() { - var baseScore = this.seedCounts[storeHouses[1-this.turn]]-this.seedCounts[storeHouses[this.turn]]; - var otherSpaces = homeSpaces[this.turn]; - var sum = 0; - for (var k = 0,len = otherSpaces.length;k0) { - features.clear(); - var len = this.seedCounts.length; - for (var i = 0;i0) { - if (nextSpace==storeHouses[this.turn]) { - features.seedStoredCount++; - } - if ((nextSpace!=storeHouses[1-this.turn])) { - nextSeedCounts[nextSpace]++; - seedCount--; - } - if (seedCount==0) { - if (nextSpace==storeHouses[this.turn]) { - features.turnContinues = true; - } - else { - if ((nextSeedCounts[nextSpace]==1)&& - (nextSpace>=firstHomeSpace[this.turn])&& - (nextSpace<=lastHomeSpace[this.turn])) { - // capture - var capturedSpace = capturedSpaces[nextSpace]; - if (capturedSpace>=0) { - features.spaceCaptured = capturedSpace; - features.capturedCount = nextSeedCounts[capturedSpace]; - nextSeedCounts[capturedSpace] = 0; - nextSeedCounts[storeHouses[this.turn]] += features.capturedCount; - features.seedStoredCount += nextSeedCounts[capturedSpace]; - } - } - } - } - nextSpace = (nextSpace+1)%14; - } - return true; - } - else { - return false; - } - } -} - -export class SeedCoords { - tx:number; - ty:number; - angle:number; - - constructor(tx:number, ty:number, angle:number) { - this.tx = tx; - this.ty = ty; - this.angle = angle; - } -} - -export class DisplayPosition extends Position { - - config:SeedCoords[][]; - - constructor(seedCounts:number[],startMove:number,turn:number) { - super(seedCounts,startMove,turn); - - this.config = []; - - for (var i = 0;i(); - } - } - - - seedCircleRect(rect:Rectangle,seedCount:number,board:Element,seed:number) { - var coords = this.config[seed]; - var sq = rect.inner(0.95).square(); - var cxo = (sq.width/2)+sq.x; - var cyo = (sq.height/2)+sq.y; - var seedNumbers = [5,7,9,11]; - var ringIndex = 0; - var ringRem = seedNumbers[ringIndex]; - var angleDelta = (2*Math.PI)/ringRem; - var angle = angleDelta; - var seedLength = sq.width/(seedNumbers.length<<1); - var crMax = sq.width/2-(seedLength/2); - var pit = createSVGInscribedCircle(sq); - if (seed<7) { - pit.setAttribute('fill','brown'); - } - else { - pit.setAttribute('fill','saddlebrown'); - } - board.appendChild(pit); - var seedsSeen = 0; - while (seedCount > 0) { - if (ringRem == 0) { - ringIndex++; - ringRem = seedNumbers[ringIndex]; - angleDelta = (2*Math.PI)/ringRem; - angle = angleDelta; - } - var tx:number; - var ty:number; - var tangle = angle; - if (coords.length>seedsSeen) { - tx = coords[seedsSeen].tx; - ty = coords[seedsSeen].ty; - tangle = coords[seedsSeen].angle; - } - else { - tx = (Math.random()*crMax)-(crMax/3); - ty = (Math.random()*crMax)-(crMax/3); - coords[seedsSeen] = new SeedCoords(tx,ty,angle); - } - var ell = createSVGEllipsePolar(tangle,seedLength,tx,ty,cxo,cyo); - board.appendChild(ell); - angle += angleDelta; - ringRem--; - seedCount--; - seedsSeen++; - } - } - - toCircleSVG() { - var seedDivisions = 14; - var board = document.createElementNS(svgNS,'svg'); - var boardRect = new Rectangle(0,0,1800,800); - board.setAttribute('width','1800'); - board.setAttribute('height','800'); - var whole = createSVGRect(boardRect); - whole.setAttribute('fill','tan'); - board.appendChild(whole); - var labPlayLab = boardRect.proportionalSplitVert(20,760,20); - var playSurface = labPlayLab[1]; - var storeMainStore = playSurface.proportionalSplitHoriz(8,48,8); - var mainPair = storeMainStore[1].subDivideVert(2); - var playerRects = [mainPair[0].subDivideHoriz(6), mainPair[1].subDivideHoriz(6)]; - // reverse top layer because storehouse on left - for (var k = 0;k<3;k++) { - var temp = playerRects[0][k]; - playerRects[0][k] = playerRects[0][5-k]; - playerRects[0][5-k] = temp; - } - var storehouses = [storeMainStore[0],storeMainStore[2]]; - var playerSeeds = this.seedCounts.length>>1; - for (var i = 0;i<2;i++) { - var player = playerRects[i]; - var storehouse = storehouses[i]; - var r:Rectangle; - for (var j = 0;j(); - } - } - } - return board; - } -} -} -`; - -export const debuggableFile = `# VS Code Mock Debug - -This is a starter sample for developing VS Code debug adapters. - -**Mock Debug** simulates a debug adapter for Visual Studio Code. -It supports *step*, *continue*, *breakpoints*, *exceptions*, and -*variable access* but it is not connected to any real debugger. - -The sample is meant as an educational piece showing how to implement a debug -adapter for VS Code. It can be used as a starting point for developing a real adapter. - -More information about how to develop a new debug adapter can be found -[here](https://code.visualstudio.com/docs/extensions/example-debuggers). -Or discuss debug adapters on Gitter: -[![Gitter Chat](https://img.shields.io/badge/chat-online-brightgreen.svg)](https://gitter.im/Microsoft/vscode) - -## Using Mock Debug - -* Install the **Mock Debug** extension in VS Code. -* Create a new 'program' file 'readme.md' and enter several lines of arbitrary text. -* Switch to the debug viewlet and press the gear dropdown. -* Select the debug environment "Mock Debug". -* Press the green 'play' button to start debugging. - -You can now 'step through' the 'readme.md' file, set and hit breakpoints, and run into exceptions (if the word exception appears in a line). - -![Mock Debug](file.jpg) - -## Build and Run - -[![build status](https://travis-ci.org/Microsoft/vscode-mock-debug.svg?branch=master)](https://travis-ci.org/Microsoft/vscode-mock-debug) -[![build status](https://ci.appveyor.com/api/projects/status/empmw5q1tk6h1fly/branch/master?svg=true)](https://ci.appveyor.com/project/weinand/vscode-mock-debug) - - -* Clone the project [https://github.com/Microsoft/vscode-mock-debug.git](https://github.com/Microsoft/vscode-mock-debug.git) -* Open the project folder in VS Code. -* Press 'F5' to build and launch Mock Debug in another VS Code window. In that window: -* Open a new workspace, create a new 'program' file 'readme.md' and enter several lines of arbitrary text. -* Switch to the debug viewlet and press the gear dropdown. -* Select the debug environment "Mock Debug". -* Press 'F5' to start debugging.`; - -export function getImageFile(): Uint8Array { - const data = atob(`/9j/4AAQSkZJRgABAQAASABIAAD/2wCEAA4ODg4ODhcODhchFxcXIS0hISEhLTktLS0tLTlFOTk5OTk5RUVFRUVFRUVSUlJSUlJgYGBgYGxsbGxsbGxsbGwBERISGxkbLxkZL3FMP0xxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcf/AABEIAFYAZAMBIgACEQEDEQH/xAB1AAACAwEBAQAAAAAAAAAAAAAABAMFBgIBBxAAAgIBAwMCBQQCAwAAAAAAAQIAAxEEBSESMUFRcRMiIzJhFIGRoQbBQlKxAQEBAQEAAAAAAAAAAAAAAAABAgADEQEBAQADAQEAAAAAAAAAAAAAARESITECQf/aAAwDAQACEQMRAD8A2LEZkLc/bKxbdYEHWoyfEze56zXpqRTTYUyPHiVrY2TVZyMzhFZMg8iYE6jcVXAusY98KMnj2lhRu+4aLoGuTNTYPV5APnyDNyPFp6EY3EsO3kxnVVLZVg8z2tw9YsXkGQpcbGIbxHQzep0vw8Jgc8n28CJJRY30lBwzf1iaa2ku/HmMV01VW/k/6hh0abTDTafpPcTytmckEewjeosAqJEj0yDo6yO/rFLzoGME5nIAXtGSM9uwnjLn8zFECw7QneITMWouR7gj9/Ep94061bjXa32WDGfzOGuCXKy9/wDc0FlFe5aX4OpHJHBHcSfT4w246bWJar6MsCwKnp9DOF0r6XRiu5snvg9hNK217vQeih0tXwzcED895R7voNfWoN9gOT2QH/2T3mHrda3Y+p9ppZuSV/qR0j6r+5ju2oun2ypOwCAASGikISzdySf5lxLsAdRPpIqw91xC/wDHvGbAAh88RnSVCjT9b8E/MYsguerTqWuYKo8k4ESTcttsPSmoQ+zCZPWPbvWqsvLE0IxCL4wPP7xEW7TXeKsvaGABOMdLef2ky7ejevX0tBWy5Qhh6jmS9IIxPm6XazbW69K56M/aeRibnSaqyytWtGCfE0+tazDhrHpCdixT5EJSWD1BPkcjsYxpN21FWEcdu0dG3hl8rIX0YqUgDqkSrq/0+6oyfOOZT7hqxqLMKMk8ARfS0fqGatAR04yCY+u3OpLt38e0rQl0tzsFrc8rxj0lqqDHMzujIXUMGPI4mjS1MTCvG8gRLddYE2811n5nHTJ9RaAsztzZ1AZhlX9fBi0VWgWzbSqahfpWfa/iSnatMuqOpVgVPIHGMzc6erS3aQVOoZSMFTK19i2pTwGA9Axx/E58b+K2M8lP6/Urp6BkA5Y+OPE112nrIFeOw8RMajQ7dWU0iAH8TyrVG0mw8EypMFuk7K9TS5RGJHiEYsuUtmEWO1KO2RGDRSVJzj1MiQhOQIx8QEYK5hGpUUJVc1lTgcDjEe1FPxqGQHBZSMiQqa8/Z38xgOoHB/aIfJNVZrdFqirsVbsfzLXT7+UQLYmcDHBlh/k+g+KP1dOCV+4efcTNbdtGq3CxQiMKyeX7CGqxqtDuK7lYK2BXnAz3JMuNZoPpDAyV5zHNt2bRbcA1S/Pjljyf7jerWxx0V4wQeZgynxrUXoUnIif629GJY595cptr1N9XJYjOfEi1G3LYMLgH1m04qxelrAtnj/qZYIvUPpMcHwYtTT8FzVaMN6+sslqVF6gcQ1sRivPccwjS314+bGYRBnqzws6FhUfL7CQ8gdI7+TDIHHgcSVGBYRznMXfUL2J5ngPUOYCpfM2tiq1tnUpVRnMe0DGtAKyQIw+mU4GJCKmrPy+I6V0lxYYIzxOCtdjZyVIMRqtPsYx8RT37+sdRhsFlHzcyC0J0kmcfqFX5cxC7VAk4OPUQtM+UVtYf7vH8iKP8SnKg5U9xHQwsGV7jxF9QnWACMEcgwlUjT4ZUE+YRRLGRehwciEpLRMAAT6SALlIQkF4kl7HEIQLwuQfac9RPeEJi5H3TruvvmEJo1QOcgGQuvVg+sITM8rDKeDHVItXkQhKgqM6esnJEIQlJf//Z`); - return Uint8Array.from([...data].map(x => x.charCodeAt(0))); -} - -// encoded from 'ŠŠ‘Š’Š“Š”Š•Š–Š—Š˜Š™ŠšŠ›ŠœŠŠžŠŸŠ Š”Š¢Š£Š¤Š„Š¦Š§ŠØŠ©ŠŖŠ«Š¬Š­Š®ŠÆŠ°Š±Š²Š³Š“ŠµŠ¶Š·ŠøŠ¹ŠŗŠ»Š¼Š½Š¾ŠæŃ€ŃŃ‚ŃƒŃ„Ń…Ń†Ń‡ŃˆŃ‰ŃŠŃ‹ŃŒŃŃŽŃ' -export const windows1251File = Uint8Array.from([192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]); - -// encoded from '中国abc' -export const gbkFile = Uint8Array.from([214, 208, 185, 250, 97, 98, 99]); diff --git a/extensions/vscode-web-playground/src/extension.ts b/extensions/vscode-web-playground/src/extension.ts deleted file mode 100644 index 1d5df92bbcc..00000000000 --- a/extensions/vscode-web-playground/src/extension.ts +++ /dev/null @@ -1,3927 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// -// ############################################################################ -// -// ! USED FOR RUNNING VSCODE OUT OF SOURCES FOR WEB ! -// ! DO NOT REMOVE ! -// -// ############################################################################ -// - -import * as vscode from 'vscode'; -import { MemFS } from './memfs'; - -declare const navigator: unknown; - -export function activate(context: vscode.ExtensionContext) { - if (typeof navigator === 'object') { // do not run under node.js - const memFs = enableFs(context); - - if (vscode.workspace.workspaceFolders?.some(f => f.uri.scheme === MemFS.scheme)) { - memFs.seed(); - enableProblems(context); - enableTasks(); - enableDebug(context, memFs); - - vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(`memfs:/sample-folder/large.ts`)); - } - } -} - -function enableFs(context: vscode.ExtensionContext): MemFS { - const memFs = new MemFS(); - context.subscriptions.push(memFs); - - return memFs; -} - -function enableProblems(context: vscode.ExtensionContext): void { - const collection = vscode.languages.createDiagnosticCollection('test'); - if (vscode.window.activeTextEditor) { - updateDiagnostics(vscode.window.activeTextEditor.document, collection); - } - context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(editor => { - if (editor) { - updateDiagnostics(editor.document, collection); - } - })); -} - -function updateDiagnostics(document: vscode.TextDocument, collection: vscode.DiagnosticCollection): void { - if (document && document.fileName === '/sample-folder/large.ts') { - collection.set(document.uri, [{ - code: '', - message: 'cannot assign twice to immutable variable `storeHouses`', - range: new vscode.Range(new vscode.Position(4, 12), new vscode.Position(4, 32)), - severity: vscode.DiagnosticSeverity.Error, - source: '', - relatedInformation: [ - new vscode.DiagnosticRelatedInformation(new vscode.Location(document.uri, new vscode.Range(new vscode.Position(1, 8), new vscode.Position(1, 9))), 'first assignment to `x`') - ] - }, { - code: '', - message: 'function does not follow naming conventions', - range: new vscode.Range(new vscode.Position(7, 10), new vscode.Position(7, 23)), - severity: vscode.DiagnosticSeverity.Warning, - source: '' - }]); - } else { - collection.clear(); - } -} - -function enableTasks(): void { - - interface CustomBuildTaskDefinition extends vscode.TaskDefinition { - /** - * The build flavor. Should be either '32' or '64'. - */ - flavor: string; - - /** - * Additional build flags - */ - flags?: string[]; - } - - class CustomBuildTaskProvider implements vscode.TaskProvider { - static CustomBuildScriptType: string = 'custombuildscript'; - private tasks: vscode.Task[] | undefined; - - // We use a CustomExecution task when state needs to be shared accross runs of the task or when - // the task requires use of some VS Code API to run. - // If you don't need to share state between runs and if you don't need to execute VS Code API in your task, - // then a simple ShellExecution or ProcessExecution should be enough. - // Since our build has this shared state, the CustomExecution is used below. - private sharedState: string | undefined; - - constructor(private workspaceRoot: string) { } - - public async provideTasks(): Promise { - return this.getTasks(); - } - - public resolveTask(_task: vscode.Task): vscode.Task | undefined { - const flavor: string = _task.definition.flavor; - if (flavor) { - const definition: CustomBuildTaskDefinition = _task.definition; - return this.getTask(definition.flavor, definition.flags ? definition.flags : [], definition); - } - return undefined; - } - - private getTasks(): vscode.Task[] { - if (this.tasks !== undefined) { - return this.tasks; - } - // In our fictional build, we have two build flavors - const flavors: string[] = ['32', '64']; - // Each flavor can have some options. - const flags: string[][] = [['watch', 'incremental'], ['incremental'], []]; - - this.tasks = []; - flavors.forEach(flavor => { - flags.forEach(flagGroup => { - this.tasks!.push(this.getTask(flavor, flagGroup)); - }); - }); - return this.tasks; - } - - private getTask(flavor: string, flags: string[], definition?: CustomBuildTaskDefinition): vscode.Task { - if (definition === undefined) { - definition = { - type: CustomBuildTaskProvider.CustomBuildScriptType, - flavor, - flags - }; - } - return new vscode.Task2(definition, vscode.TaskScope.Workspace, `${flavor} ${flags.join(' ')}`, - CustomBuildTaskProvider.CustomBuildScriptType, new vscode.CustomExecution(async (): Promise => { - // When the task is executed, this callback will run. Here, we setup for running the task. - return new CustomBuildTaskTerminal(this.workspaceRoot, flavor, flags, () => this.sharedState, (state: string) => this.sharedState = state); - })); - } - } - - class CustomBuildTaskTerminal implements vscode.Pseudoterminal { - private writeEmitter = new vscode.EventEmitter(); - onDidWrite: vscode.Event = this.writeEmitter.event; - private closeEmitter = new vscode.EventEmitter(); - onDidClose?: vscode.Event = this.closeEmitter.event; - - private fileWatcher: vscode.FileSystemWatcher | undefined; - - constructor(private workspaceRoot: string, _flavor: string, private flags: string[], private getSharedState: () => string | undefined, private setSharedState: (state: string) => void) { - } - - open(_initialDimensions: vscode.TerminalDimensions | undefined): void { - // At this point we can start using the terminal. - if (this.flags.indexOf('watch') > -1) { - let pattern = this.workspaceRoot + '/customBuildFile'; - this.fileWatcher = vscode.workspace.createFileSystemWatcher(pattern); - this.fileWatcher.onDidChange(() => this.doBuild()); - this.fileWatcher.onDidCreate(() => this.doBuild()); - this.fileWatcher.onDidDelete(() => this.doBuild()); - } - this.doBuild(); - } - - close(): void { - // The terminal has been closed. Shutdown the build. - if (this.fileWatcher) { - this.fileWatcher.dispose(); - } - } - - private async doBuild(): Promise { - return new Promise((resolve) => { - this.writeEmitter.fire('Starting build...\r\n'); - let isIncremental = this.flags.indexOf('incremental') > -1; - if (isIncremental) { - if (this.getSharedState()) { - this.writeEmitter.fire('Using last build results: ' + this.getSharedState() + '\r\n'); - } else { - isIncremental = false; - this.writeEmitter.fire('No result from last build. Doing full build.\r\n'); - } - } - - // Since we don't actually build anything in this example set a timeout instead. - setTimeout(() => { - const date = new Date(); - this.setSharedState(date.toTimeString() + ' ' + date.toDateString()); - this.writeEmitter.fire('Build complete.\r\n\r\n'); - if (this.flags.indexOf('watch') === -1) { - this.closeEmitter.fire(); - resolve(); - } - }, isIncremental ? 1000 : 4000); - }); - } - } - - vscode.tasks.registerTaskProvider(CustomBuildTaskProvider.CustomBuildScriptType, new CustomBuildTaskProvider(vscode.workspace.rootPath!)); -} - -//--------------------------------------------------------------------------- -// DEBUG -//--------------------------------------------------------------------------- - -function enableDebug(context: vscode.ExtensionContext, memFs: MemFS): void { - context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('mock', new MockConfigurationProvider())); - context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('mock', new MockDebugAdapterDescriptorFactory(memFs))); -} - -/** - * Declaration module describing the VS Code debug protocol. - * Auto-generated from json schema. Do not edit manually. - */ -declare module DebugProtocol { - - /** Base class of requests, responses, and events. */ - export interface ProtocolMessage { - /** Sequence number (also known as message ID). For protocol messages of type 'request' this ID can be used to cancel the request. */ - seq: number; - /** Message type. - Values: 'request', 'response', 'event', etc. - */ - type: string; - } - - /** A client or debug adapter initiated request. */ - export interface Request extends ProtocolMessage { - // type: 'request'; - /** The command to execute. */ - command: string; - /** Object containing arguments for the command. */ - arguments?: any; - } - - /** A debug adapter initiated event. */ - export interface Event extends ProtocolMessage { - // type: 'event'; - /** Type of event. */ - event: string; - /** Event-specific information. */ - body?: any; - } - - /** Response for a request. */ - export interface Response extends ProtocolMessage { - // type: 'response'; - /** Sequence number of the corresponding request. */ - request_seq: number; - /** Outcome of the request. - If true, the request was successful and the 'body' attribute may contain the result of the request. - If the value is false, the attribute 'message' contains the error in short form and the 'body' may contain additional information (see 'ErrorResponse.body.error'). - */ - success: boolean; - /** The command requested. */ - command: string; - /** Contains the raw error in short form if 'success' is false. - This raw error might be interpreted by the frontend and is not shown in the UI. - Some predefined values exist. - Values: - 'cancelled': request was cancelled. - etc. - */ - message?: string; - /** Contains request result if success is true and optional error details if success is false. */ - body?: any; - } - - /** On error (whenever 'success' is false), the body can provide more details. */ - export interface ErrorResponse extends Response { - body: { - /** An optional, structured error message. */ - error?: Message; - }; - } - - /** Cancel request; value of command field is 'cancel'. - The 'cancel' request is used by the frontend to indicate that it is no longer interested in the result produced by a specific request issued earlier. - This request has a hint characteristic: a debug adapter can only be expected to make a 'best effort' in honouring this request but there are no guarantees. - The 'cancel' request may return an error if it could not cancel an operation but a frontend should refrain from presenting this error to end users. - A frontend client should only call this request if the capability 'supportsCancelRequest' is true. - The request that got canceled still needs to send a response back. - This can either be a normal result ('success' attribute true) or an error response ('success' attribute false and the 'message' set to 'cancelled'). - Returning partial results from a cancelled request is possible but please note that a frontend client has no generic way for detecting that a response is partial or not. - */ - export interface CancelRequest extends Request { - // command: 'cancel'; - arguments?: CancelArguments; - } - - /** Arguments for 'cancel' request. */ - export interface CancelArguments { - /** The ID (attribute 'seq') of the request to cancel. */ - requestId?: number; - } - - /** Response to 'cancel' request. This is just an acknowledgement, so no body field is required. */ - export interface CancelResponse extends Response { - } - - /** Event message for 'initialized' event type. - This event indicates that the debug adapter is ready to accept configuration requests (e.g. SetBreakpointsRequest, SetExceptionBreakpointsRequest). - A debug adapter is expected to send this event when it is ready to accept configuration requests (but not before the 'initialize' request has finished). - The sequence of events/requests is as follows: - - adapters sends 'initialized' event (after the 'initialize' request has returned) - - frontend sends zero or more 'setBreakpoints' requests - - frontend sends one 'setFunctionBreakpoints' request - - frontend sends a 'setExceptionBreakpoints' request if one or more 'exceptionBreakpointFilters' have been defined (or if 'supportsConfigurationDoneRequest' is not defined or false) - - frontend sends other future configuration requests - - frontend sends one 'configurationDone' request to indicate the end of the configuration. - */ - export interface InitializedEvent extends Event { - // event: 'initialized'; - } - - /** Event message for 'stopped' event type. - The event indicates that the execution of the debuggee has stopped due to some condition. - This can be caused by a break point previously set, a stepping action has completed, by executing a debugger statement etc. - */ - export interface StoppedEvent extends Event { - // event: 'stopped'; - body: { - /** The reason for the event. - For backward compatibility this string is shown in the UI if the 'description' attribute is missing (but it must not be translated). - Values: 'step', 'breakpoint', 'exception', 'pause', 'entry', 'goto', 'function breakpoint', 'data breakpoint', etc. - */ - reason: string; - /** The full reason for the event, e.g. 'Paused on exception'. This string is shown in the UI as is and must be translated. */ - description?: string; - /** The thread which was stopped. */ - threadId?: number; - /** A value of true hints to the frontend that this event should not change the focus. */ - preserveFocusHint?: boolean; - /** Additional information. E.g. if reason is 'exception', text contains the exception name. This string is shown in the UI. */ - text?: string; - /** If 'allThreadsStopped' is true, a debug adapter can announce that all threads have stopped. - - The client should use this information to enable that all threads can be expanded to access their stacktraces. - - If the attribute is missing or false, only the thread with the given threadId can be expanded. - */ - allThreadsStopped?: boolean; - }; - } - - /** Event message for 'continued' event type. - The event indicates that the execution of the debuggee has continued. - Please note: a debug adapter is not expected to send this event in response to a request that implies that execution continues, e.g. 'launch' or 'continue'. - It is only necessary to send a 'continued' event if there was no previous request that implied this. - */ - export interface ContinuedEvent extends Event { - // event: 'continued'; - body: { - /** The thread which was continued. */ - threadId: number; - /** If 'allThreadsContinued' is true, a debug adapter can announce that all threads have continued. */ - allThreadsContinued?: boolean; - }; - } - - /** Event message for 'exited' event type. - The event indicates that the debuggee has exited and returns its exit code. - */ - export interface ExitedEvent extends Event { - // event: 'exited'; - body: { - /** The exit code returned from the debuggee. */ - exitCode: number; - }; - } - - /** Event message for 'terminated' event type. - The event indicates that debugging of the debuggee has terminated. This does **not** mean that the debuggee itself has exited. - */ - export interface TerminatedEvent extends Event { - // event: 'terminated'; - body?: { - /** A debug adapter may set 'restart' to true (or to an arbitrary object) to request that the front end restarts the session. - The value is not interpreted by the client and passed unmodified as an attribute '__restart' to the 'launch' and 'attach' requests. - */ - restart?: any; - }; - } - - /** Event message for 'thread' event type. - The event indicates that a thread has started or exited. - */ - export interface ThreadEvent extends Event { - // event: 'thread'; - body: { - /** The reason for the event. - Values: 'started', 'exited', etc. - */ - reason: string; - /** The identifier of the thread. */ - threadId: number; - }; - } - - /** Event message for 'output' event type. - The event indicates that the target has produced some output. - */ - export interface OutputEvent extends Event { - // event: 'output'; - body: { - /** The output category. If not specified, 'console' is assumed. - Values: 'console', 'stdout', 'stderr', 'telemetry', etc. - */ - category?: string; - /** The output to report. */ - output: string; - /** If an attribute 'variablesReference' exists and its value is > 0, the output contains objects which can be retrieved by passing 'variablesReference' to the 'variables' request. The value should be less than or equal to 2147483647 (2^31 - 1). */ - variablesReference?: number; - /** An optional source location where the output was produced. */ - source?: Source; - /** An optional source location line where the output was produced. */ - line?: number; - /** An optional source location column where the output was produced. */ - column?: number; - /** Optional data to report. For the 'telemetry' category the data will be sent to telemetry, for the other categories the data is shown in JSON format. */ - data?: any; - }; - } - - /** Event message for 'breakpoint' event type. - The event indicates that some information about a breakpoint has changed. - */ - export interface BreakpointEvent extends Event { - // event: 'breakpoint'; - body: { - /** The reason for the event. - Values: 'changed', 'new', 'removed', etc. - */ - reason: string; - /** The 'id' attribute is used to find the target breakpoint and the other attributes are used as the new values. */ - breakpoint: Breakpoint; - }; - } - - /** Event message for 'module' event type. - The event indicates that some information about a module has changed. - */ - export interface ModuleEvent extends Event { - // event: 'module'; - body: { - /** The reason for the event. */ - reason: 'new' | 'changed' | 'removed'; - /** The new, changed, or removed module. In case of 'removed' only the module id is used. */ - module: Module; - }; - } - - /** Event message for 'loadedSource' event type. - The event indicates that some source has been added, changed, or removed from the set of all loaded sources. - */ - export interface LoadedSourceEvent extends Event { - // event: 'loadedSource'; - body: { - /** The reason for the event. */ - reason: 'new' | 'changed' | 'removed'; - /** The new, changed, or removed source. */ - source: Source; - }; - } - - /** Event message for 'process' event type. - The event indicates that the debugger has begun debugging a new process. Either one that it has launched, or one that it has attached to. - */ - export interface ProcessEvent extends Event { - // event: 'process'; - body: { - /** The logical name of the process. This is usually the full path to process's executable file. Example: /home/example/myproj/program.js. */ - name: string; - /** The system process id of the debugged process. This property will be missing for non-system processes. */ - systemProcessId?: number; - /** If true, the process is running on the same computer as the debug adapter. */ - isLocalProcess?: boolean; - /** Describes how the debug engine started debugging this process. - 'launch': Process was launched under the debugger. - 'attach': Debugger attached to an existing process. - 'attachForSuspendedLaunch': A project launcher component has launched a new process in a suspended state and then asked the debugger to attach. - */ - startMethod?: 'launch' | 'attach' | 'attachForSuspendedLaunch'; - /** The size of a pointer or address for this process, in bits. This value may be used by clients when formatting addresses for display. */ - pointerSize?: number; - }; - } - - /** Event message for 'capabilities' event type. - The event indicates that one or more capabilities have changed. - Since the capabilities are dependent on the frontend and its UI, it might not be possible to change that at random times (or too late). - Consequently this event has a hint characteristic: a frontend can only be expected to make a 'best effort' in honouring individual capabilities but there are no guarantees. - Only changed capabilities need to be included, all other capabilities keep their values. - */ - export interface CapabilitiesEvent extends Event { - // event: 'capabilities'; - body: { - /** The set of updated capabilities. */ - capabilities: Capabilities; - }; - } - - /** RunInTerminal request; value of command field is 'runInTerminal'. - This request is sent from the debug adapter to the client to run a command in a terminal. This is typically used to launch the debuggee in a terminal provided by the client. - */ - export interface RunInTerminalRequest extends Request { - // command: 'runInTerminal'; - arguments: RunInTerminalRequestArguments; - } - - /** Arguments for 'runInTerminal' request. */ - export interface RunInTerminalRequestArguments { - /** What kind of terminal to launch. */ - kind?: 'integrated' | 'external'; - /** Optional title of the terminal. */ - title?: string; - /** Working directory of the command. */ - cwd: string; - /** List of arguments. The first argument is the command to run. */ - args: string[]; - /** Environment key-value pairs that are added to or removed from the default environment. */ - env?: { [key: string]: string | null; }; - } - - /** Response to 'runInTerminal' request. */ - export interface RunInTerminalResponse extends Response { - body: { - /** The process ID. The value should be less than or equal to 2147483647 (2^31 - 1). */ - processId?: number; - /** The process ID of the terminal shell. The value should be less than or equal to 2147483647 (2^31 - 1). */ - shellProcessId?: number; - }; - } - - /** Initialize request; value of command field is 'initialize'. - The 'initialize' request is sent as the first request from the client to the debug adapter in order to configure it with client capabilities and to retrieve capabilities from the debug adapter. - Until the debug adapter has responded to with an 'initialize' response, the client must not send any additional requests or events to the debug adapter. In addition the debug adapter is not allowed to send any requests or events to the client until it has responded with an 'initialize' response. - The 'initialize' request may only be sent once. - */ - export interface InitializeRequest extends Request { - // command: 'initialize'; - arguments: InitializeRequestArguments; - } - - /** Arguments for 'initialize' request. */ - export interface InitializeRequestArguments { - /** The ID of the (frontend) client using this adapter. */ - clientID?: string; - /** The human readable name of the (frontend) client using this adapter. */ - clientName?: string; - /** The ID of the debug adapter. */ - adapterID: string; - /** The ISO-639 locale of the (frontend) client using this adapter, e.g. en-US or de-CH. */ - locale?: string; - /** If true all line numbers are 1-based (default). */ - linesStartAt1?: boolean; - /** If true all column numbers are 1-based (default). */ - columnsStartAt1?: boolean; - /** Determines in what format paths are specified. The default is 'path', which is the native format. - Values: 'path', 'uri', etc. - */ - pathFormat?: string; - /** Client supports the optional type attribute for variables. */ - supportsVariableType?: boolean; - /** Client supports the paging of variables. */ - supportsVariablePaging?: boolean; - /** Client supports the runInTerminal request. */ - supportsRunInTerminalRequest?: boolean; - /** Client supports memory references. */ - supportsMemoryReferences?: boolean; - } - - /** Response to 'initialize' request. */ - export interface InitializeResponse extends Response { - /** The capabilities of this debug adapter. */ - body?: Capabilities; - } - - /** ConfigurationDone request; value of command field is 'configurationDone'. - The client of the debug protocol must send this request at the end of the sequence of configuration requests (which was started by the 'initialized' event). - */ - export interface ConfigurationDoneRequest extends Request { - // command: 'configurationDone'; - arguments?: ConfigurationDoneArguments; - } - - /** Arguments for 'configurationDone' request. */ - export interface ConfigurationDoneArguments { - } - - /** Response to 'configurationDone' request. This is just an acknowledgement, so no body field is required. */ - export interface ConfigurationDoneResponse extends Response { - } - - /** Launch request; value of command field is 'launch'. - The launch request is sent from the client to the debug adapter to start the debuggee with or without debugging (if 'noDebug' is true). Since launching is debugger/runtime specific, the arguments for this request are not part of this specification. - */ - export interface LaunchRequest extends Request { - // command: 'launch'; - arguments: LaunchRequestArguments; - } - - /** Arguments for 'launch' request. Additional attributes are implementation specific. */ - export interface LaunchRequestArguments { - /** If noDebug is true the launch request should launch the program without enabling debugging. */ - noDebug?: boolean; - /** Optional data from the previous, restarted session. - The data is sent as the 'restart' attribute of the 'terminated' event. - The client should leave the data intact. - */ - __restart?: any; - } - - /** Response to 'launch' request. This is just an acknowledgement, so no body field is required. */ - export interface LaunchResponse extends Response { - } - - /** Attach request; value of command field is 'attach'. - The attach request is sent from the client to the debug adapter to attach to a debuggee that is already running. Since attaching is debugger/runtime specific, the arguments for this request are not part of this specification. - */ - export interface AttachRequest extends Request { - // command: 'attach'; - arguments: AttachRequestArguments; - } - - /** Arguments for 'attach' request. Additional attributes are implementation specific. */ - export interface AttachRequestArguments { - /** Optional data from the previous, restarted session. - The data is sent as the 'restart' attribute of the 'terminated' event. - The client should leave the data intact. - */ - __restart?: any; - } - - /** Response to 'attach' request. This is just an acknowledgement, so no body field is required. */ - export interface AttachResponse extends Response { - } - - /** Restart request; value of command field is 'restart'. - Restarts a debug session. If the capability 'supportsRestartRequest' is missing or has the value false, - the client will implement 'restart' by terminating the debug adapter first and then launching it anew. - A debug adapter can override this default behaviour by implementing a restart request - and setting the capability 'supportsRestartRequest' to true. - */ - export interface RestartRequest extends Request { - // command: 'restart'; - arguments?: RestartArguments; - } - - /** Arguments for 'restart' request. */ - export interface RestartArguments { - } - - /** Response to 'restart' request. This is just an acknowledgement, so no body field is required. */ - export interface RestartResponse extends Response { - } - - /** Disconnect request; value of command field is 'disconnect'. - The 'disconnect' request is sent from the client to the debug adapter in order to stop debugging. It asks the debug adapter to disconnect from the debuggee and to terminate the debug adapter. If the debuggee has been started with the 'launch' request, the 'disconnect' request terminates the debuggee. If the 'attach' request was used to connect to the debuggee, 'disconnect' does not terminate the debuggee. This behavior can be controlled with the 'terminateDebuggee' argument (if supported by the debug adapter). - */ - export interface DisconnectRequest extends Request { - // command: 'disconnect'; - arguments?: DisconnectArguments; - } - - /** Arguments for 'disconnect' request. */ - export interface DisconnectArguments { - /** A value of true indicates that this 'disconnect' request is part of a restart sequence. */ - restart?: boolean; - /** Indicates whether the debuggee should be terminated when the debugger is disconnected. - If unspecified, the debug adapter is free to do whatever it thinks is best. - A client can only rely on this attribute being properly honored if a debug adapter returns true for the 'supportTerminateDebuggee' capability. - */ - terminateDebuggee?: boolean; - } - - /** Response to 'disconnect' request. This is just an acknowledgement, so no body field is required. */ - export interface DisconnectResponse extends Response { - } - - /** Terminate request; value of command field is 'terminate'. - The 'terminate' request is sent from the client to the debug adapter in order to give the debuggee a chance for terminating itself. - */ - export interface TerminateRequest extends Request { - // command: 'terminate'; - arguments?: TerminateArguments; - } - - /** Arguments for 'terminate' request. */ - export interface TerminateArguments { - /** A value of true indicates that this 'terminate' request is part of a restart sequence. */ - restart?: boolean; - } - - /** Response to 'terminate' request. This is just an acknowledgement, so no body field is required. */ - export interface TerminateResponse extends Response { - } - - /** BreakpointLocations request; value of command field is 'breakpointLocations'. - The 'breakpointLocations' request returns all possible locations for source breakpoints in a given range. - */ - export interface BreakpointLocationsRequest extends Request { - // command: 'breakpointLocations'; - arguments?: BreakpointLocationsArguments; - } - - /** Arguments for 'breakpointLocations' request. */ - export interface BreakpointLocationsArguments { - /** The source location of the breakpoints; either 'source.path' or 'source.reference' must be specified. */ - source: Source; - /** Start line of range to search possible breakpoint locations in. If only the line is specified, the request returns all possible locations in that line. */ - line: number; - /** Optional start column of range to search possible breakpoint locations in. If no start column is given, the first column in the start line is assumed. */ - column?: number; - /** Optional end line of range to search possible breakpoint locations in. If no end line is given, then the end line is assumed to be the start line. */ - endLine?: number; - /** Optional end column of range to search possible breakpoint locations in. If no end column is given, then it is assumed to be in the last column of the end line. */ - endColumn?: number; - } - - /** Response to 'breakpointLocations' request. - Contains possible locations for source breakpoints. - */ - export interface BreakpointLocationsResponse extends Response { - body: { - /** Sorted set of possible breakpoint locations. */ - breakpoints: BreakpointLocation[]; - }; - } - - /** SetBreakpoints request; value of command field is 'setBreakpoints'. - Sets multiple breakpoints for a single source and clears all previous breakpoints in that source. - To clear all breakpoint for a source, specify an empty array. - When a breakpoint is hit, a 'stopped' event (with reason 'breakpoint') is generated. - */ - export interface SetBreakpointsRequest extends Request { - // command: 'setBreakpoints'; - arguments: SetBreakpointsArguments; - } - - /** Arguments for 'setBreakpoints' request. */ - export interface SetBreakpointsArguments { - /** The source location of the breakpoints; either 'source.path' or 'source.reference' must be specified. */ - source: Source; - /** The code locations of the breakpoints. */ - breakpoints?: SourceBreakpoint[]; - /** Deprecated: The code locations of the breakpoints. */ - lines?: number[]; - /** A value of true indicates that the underlying source has been modified which results in new breakpoint locations. */ - sourceModified?: boolean; - } - - /** Response to 'setBreakpoints' request. - Returned is information about each breakpoint created by this request. - This includes the actual code location and whether the breakpoint could be verified. - The breakpoints returned are in the same order as the elements of the 'breakpoints' - (or the deprecated 'lines') array in the arguments. - */ - export interface SetBreakpointsResponse extends Response { - body: { - /** Information about the breakpoints. The array elements are in the same order as the elements of the 'breakpoints' (or the deprecated 'lines') array in the arguments. */ - breakpoints: Breakpoint[]; - }; - } - - /** SetFunctionBreakpoints request; value of command field is 'setFunctionBreakpoints'. - Replaces all existing function breakpoints with new function breakpoints. - To clear all function breakpoints, specify an empty array. - When a function breakpoint is hit, a 'stopped' event (with reason 'function breakpoint') is generated. - */ - export interface SetFunctionBreakpointsRequest extends Request { - // command: 'setFunctionBreakpoints'; - arguments: SetFunctionBreakpointsArguments; - } - - /** Arguments for 'setFunctionBreakpoints' request. */ - export interface SetFunctionBreakpointsArguments { - /** The function names of the breakpoints. */ - breakpoints: FunctionBreakpoint[]; - } - - /** Response to 'setFunctionBreakpoints' request. - Returned is information about each breakpoint created by this request. - */ - export interface SetFunctionBreakpointsResponse extends Response { - body: { - /** Information about the breakpoints. The array elements correspond to the elements of the 'breakpoints' array. */ - breakpoints: Breakpoint[]; - }; - } - - /** SetExceptionBreakpoints request; value of command field is 'setExceptionBreakpoints'. - The request configures the debuggers response to thrown exceptions. If an exception is configured to break, a 'stopped' event is fired (with reason 'exception'). - */ - export interface SetExceptionBreakpointsRequest extends Request { - // command: 'setExceptionBreakpoints'; - arguments: SetExceptionBreakpointsArguments; - } - - /** Arguments for 'setExceptionBreakpoints' request. */ - export interface SetExceptionBreakpointsArguments { - /** IDs of checked exception options. The set of IDs is returned via the 'exceptionBreakpointFilters' capability. */ - filters: string[]; - /** Configuration options for selected exceptions. */ - exceptionOptions?: ExceptionOptions[]; - } - - /** Response to 'setExceptionBreakpoints' request. This is just an acknowledgement, so no body field is required. */ - export interface SetExceptionBreakpointsResponse extends Response { - } - - /** DataBreakpointInfo request; value of command field is 'dataBreakpointInfo'. - Obtains information on a possible data breakpoint that could be set on an expression or variable. - */ - export interface DataBreakpointInfoRequest extends Request { - // command: 'dataBreakpointInfo'; - arguments: DataBreakpointInfoArguments; - } - - /** Arguments for 'dataBreakpointInfo' request. */ - export interface DataBreakpointInfoArguments { - /** Reference to the Variable container if the data breakpoint is requested for a child of the container. */ - variablesReference?: number; - /** The name of the Variable's child to obtain data breakpoint information for. If variableReference isn’t provided, this can be an expression. */ - name: string; - } - - /** Response to 'dataBreakpointInfo' request. */ - export interface DataBreakpointInfoResponse extends Response { - body: { - /** An identifier for the data on which a data breakpoint can be registered with the setDataBreakpoints request or null if no data breakpoint is available. */ - dataId: string | null; - /** UI string that describes on what data the breakpoint is set on or why a data breakpoint is not available. */ - description: string; - /** Optional attribute listing the available access types for a potential data breakpoint. A UI frontend could surface this information. */ - accessTypes?: DataBreakpointAccessType[]; - /** Optional attribute indicating that a potential data breakpoint could be persisted across sessions. */ - canPersist?: boolean; - }; - } - - /** SetDataBreakpoints request; value of command field is 'setDataBreakpoints'. - Replaces all existing data breakpoints with new data breakpoints. - To clear all data breakpoints, specify an empty array. - When a data breakpoint is hit, a 'stopped' event (with reason 'data breakpoint') is generated. - */ - export interface SetDataBreakpointsRequest extends Request { - // command: 'setDataBreakpoints'; - arguments: SetDataBreakpointsArguments; - } - - /** Arguments for 'setDataBreakpoints' request. */ - export interface SetDataBreakpointsArguments { - /** The contents of this array replaces all existing data breakpoints. An empty array clears all data breakpoints. */ - breakpoints: DataBreakpoint[]; - } - - /** Response to 'setDataBreakpoints' request. - Returned is information about each breakpoint created by this request. - */ - export interface SetDataBreakpointsResponse extends Response { - body: { - /** Information about the data breakpoints. The array elements correspond to the elements of the input argument 'breakpoints' array. */ - breakpoints: Breakpoint[]; - }; - } - - /** Continue request; value of command field is 'continue'. - The request starts the debuggee to run again. - */ - export interface ContinueRequest extends Request { - // command: 'continue'; - arguments: ContinueArguments; - } - - /** Arguments for 'continue' request. */ - export interface ContinueArguments { - /** Continue execution for the specified thread (if possible). If the backend cannot continue on a single thread but will continue on all threads, it should set the 'allThreadsContinued' attribute in the response to true. */ - threadId: number; - } - - /** Response to 'continue' request. */ - export interface ContinueResponse extends Response { - body: { - /** If true, the 'continue' request has ignored the specified thread and continued all threads instead. If this attribute is missing a value of 'true' is assumed for backward compatibility. */ - allThreadsContinued?: boolean; - }; - } - - /** Next request; value of command field is 'next'. - The request starts the debuggee to run again for one step. - The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed. - */ - export interface NextRequest extends Request { - // command: 'next'; - arguments: NextArguments; - } - - /** Arguments for 'next' request. */ - export interface NextArguments { - /** Execute 'next' for this thread. */ - threadId: number; - } - - /** Response to 'next' request. This is just an acknowledgement, so no body field is required. */ - export interface NextResponse extends Response { - } - - /** StepIn request; value of command field is 'stepIn'. - The request starts the debuggee to step into a function/method if possible. - If it cannot step into a target, 'stepIn' behaves like 'next'. - The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed. - If there are multiple function/method calls (or other targets) on the source line, - the optional argument 'targetId' can be used to control into which target the 'stepIn' should occur. - The list of possible targets for a given source line can be retrieved via the 'stepInTargets' request. - */ - export interface StepInRequest extends Request { - // command: 'stepIn'; - arguments: StepInArguments; - } - - /** Arguments for 'stepIn' request. */ - export interface StepInArguments { - /** Execute 'stepIn' for this thread. */ - threadId: number; - /** Optional id of the target to step into. */ - targetId?: number; - } - - /** Response to 'stepIn' request. This is just an acknowledgement, so no body field is required. */ - export interface StepInResponse extends Response { - } - - /** StepOut request; value of command field is 'stepOut'. - The request starts the debuggee to run again for one step. - The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed. - */ - export interface StepOutRequest extends Request { - // command: 'stepOut'; - arguments: StepOutArguments; - } - - /** Arguments for 'stepOut' request. */ - export interface StepOutArguments { - /** Execute 'stepOut' for this thread. */ - threadId: number; - } - - /** Response to 'stepOut' request. This is just an acknowledgement, so no body field is required. */ - export interface StepOutResponse extends Response { - } - - /** StepBack request; value of command field is 'stepBack'. - The request starts the debuggee to run one step backwards. - The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed. Clients should only call this request if the capability 'supportsStepBack' is true. - */ - export interface StepBackRequest extends Request { - // command: 'stepBack'; - arguments: StepBackArguments; - } - - /** Arguments for 'stepBack' request. */ - export interface StepBackArguments { - /** Execute 'stepBack' for this thread. */ - threadId: number; - } - - /** Response to 'stepBack' request. This is just an acknowledgement, so no body field is required. */ - export interface StepBackResponse extends Response { - } - - /** ReverseContinue request; value of command field is 'reverseContinue'. - The request starts the debuggee to run backward. Clients should only call this request if the capability 'supportsStepBack' is true. - */ - export interface ReverseContinueRequest extends Request { - // command: 'reverseContinue'; - arguments: ReverseContinueArguments; - } - - /** Arguments for 'reverseContinue' request. */ - export interface ReverseContinueArguments { - /** Execute 'reverseContinue' for this thread. */ - threadId: number; - } - - /** Response to 'reverseContinue' request. This is just an acknowledgement, so no body field is required. */ - export interface ReverseContinueResponse extends Response { - } - - /** RestartFrame request; value of command field is 'restartFrame'. - The request restarts execution of the specified stackframe. - The debug adapter first sends the response and then a 'stopped' event (with reason 'restart') after the restart has completed. - */ - export interface RestartFrameRequest extends Request { - // command: 'restartFrame'; - arguments: RestartFrameArguments; - } - - /** Arguments for 'restartFrame' request. */ - export interface RestartFrameArguments { - /** Restart this stackframe. */ - frameId: number; - } - - /** Response to 'restartFrame' request. This is just an acknowledgement, so no body field is required. */ - export interface RestartFrameResponse extends Response { - } - - /** Goto request; value of command field is 'goto'. - The request sets the location where the debuggee will continue to run. - This makes it possible to skip the execution of code or to executed code again. - The code between the current location and the goto target is not executed but skipped. - The debug adapter first sends the response and then a 'stopped' event with reason 'goto'. - */ - export interface GotoRequest extends Request { - // command: 'goto'; - arguments: GotoArguments; - } - - /** Arguments for 'goto' request. */ - export interface GotoArguments { - /** Set the goto target for this thread. */ - threadId: number; - /** The location where the debuggee will continue to run. */ - targetId: number; - } - - /** Response to 'goto' request. This is just an acknowledgement, so no body field is required. */ - export interface GotoResponse extends Response { - } - - /** Pause request; value of command field is 'pause'. - The request suspends the debuggee. - The debug adapter first sends the response and then a 'stopped' event (with reason 'pause') after the thread has been paused successfully. - */ - export interface PauseRequest extends Request { - // command: 'pause'; - arguments: PauseArguments; - } - - /** Arguments for 'pause' request. */ - export interface PauseArguments { - /** Pause execution for this thread. */ - threadId: number; - } - - /** Response to 'pause' request. This is just an acknowledgement, so no body field is required. */ - export interface PauseResponse extends Response { - } - - /** StackTrace request; value of command field is 'stackTrace'. - The request returns a stacktrace from the current execution state. - */ - export interface StackTraceRequest extends Request { - // command: 'stackTrace'; - arguments: StackTraceArguments; - } - - /** Arguments for 'stackTrace' request. */ - export interface StackTraceArguments { - /** Retrieve the stacktrace for this thread. */ - threadId: number; - /** The index of the first frame to return; if omitted frames start at 0. */ - startFrame?: number; - /** The maximum number of frames to return. If levels is not specified or 0, all frames are returned. */ - levels?: number; - /** Specifies details on how to format the stack frames. */ - format?: StackFrameFormat; - } - - /** Response to 'stackTrace' request. */ - export interface StackTraceResponse extends Response { - body: { - /** The frames of the stackframe. If the array has length zero, there are no stackframes available. - This means that there is no location information available. - */ - stackFrames: StackFrame[]; - /** The total number of frames available. */ - totalFrames?: number; - }; - } - - /** Scopes request; value of command field is 'scopes'. - The request returns the variable scopes for a given stackframe ID. - */ - export interface ScopesRequest extends Request { - // command: 'scopes'; - arguments: ScopesArguments; - } - - /** Arguments for 'scopes' request. */ - export interface ScopesArguments { - /** Retrieve the scopes for this stackframe. */ - frameId: number; - } - - /** Response to 'scopes' request. */ - export interface ScopesResponse extends Response { - body: { - /** The scopes of the stackframe. If the array has length zero, there are no scopes available. */ - scopes: Scope[]; - }; - } - - /** Variables request; value of command field is 'variables'. - Retrieves all child variables for the given variable reference. - An optional filter can be used to limit the fetched children to either named or indexed children. - */ - export interface VariablesRequest extends Request { - // command: 'variables'; - arguments: VariablesArguments; - } - - /** Arguments for 'variables' request. */ - export interface VariablesArguments { - /** The Variable reference. */ - variablesReference: number; - /** Optional filter to limit the child variables to either named or indexed. If omitted, both types are fetched. */ - filter?: 'indexed' | 'named'; - /** The index of the first variable to return; if omitted children start at 0. */ - start?: number; - /** The number of variables to return. If count is missing or 0, all variables are returned. */ - count?: number; - /** Specifies details on how to format the Variable values. */ - format?: ValueFormat; - } - - /** Response to 'variables' request. */ - export interface VariablesResponse extends Response { - body: { - /** All (or a range) of variables for the given variable reference. */ - variables: Variable[]; - }; - } - - /** SetVariable request; value of command field is 'setVariable'. - Set the variable with the given name in the variable container to a new value. - */ - export interface SetVariableRequest extends Request { - // command: 'setVariable'; - arguments: SetVariableArguments; - } - - /** Arguments for 'setVariable' request. */ - export interface SetVariableArguments { - /** The reference of the variable container. */ - variablesReference: number; - /** The name of the variable in the container. */ - name: string; - /** The value of the variable. */ - value: string; - /** Specifies details on how to format the response value. */ - format?: ValueFormat; - } - - /** Response to 'setVariable' request. */ - export interface SetVariableResponse extends Response { - body: { - /** The new value of the variable. */ - value: string; - /** The type of the new value. Typically shown in the UI when hovering over the value. */ - type?: string; - /** If variablesReference is > 0, the new value is structured and its children can be retrieved by passing variablesReference to the VariablesRequest. The value should be less than or equal to 2147483647 (2^31 - 1). */ - variablesReference?: number; - /** The number of named child variables. - The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1). - */ - namedVariables?: number; - /** The number of indexed child variables. - The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1). - */ - indexedVariables?: number; - }; - } - - /** Source request; value of command field is 'source'. - The request retrieves the source code for a given source reference. - */ - export interface SourceRequest extends Request { - // command: 'source'; - arguments: SourceArguments; - } - - /** Arguments for 'source' request. */ - export interface SourceArguments { - /** Specifies the source content to load. Either source.path or source.sourceReference must be specified. */ - source?: Source; - /** The reference to the source. This is the same as source.sourceReference. This is provided for backward compatibility since old backends do not understand the 'source' attribute. */ - sourceReference: number; - } - - /** Response to 'source' request. */ - export interface SourceResponse extends Response { - body: { - /** Content of the source reference. */ - content: string; - /** Optional content type (mime type) of the source. */ - mimeType?: string; - }; - } - - /** Threads request; value of command field is 'threads'. - The request retrieves a list of all threads. - */ - export interface ThreadsRequest extends Request { - // command: 'threads'; - } - - /** Response to 'threads' request. */ - export interface ThreadsResponse extends Response { - body: { - /** All threads. */ - threads: Thread[]; - }; - } - - /** TerminateThreads request; value of command field is 'terminateThreads'. - The request terminates the threads with the given ids. - */ - export interface TerminateThreadsRequest extends Request { - // command: 'terminateThreads'; - arguments: TerminateThreadsArguments; - } - - /** Arguments for 'terminateThreads' request. */ - export interface TerminateThreadsArguments { - /** Ids of threads to be terminated. */ - threadIds?: number[]; - } - - /** Response to 'terminateThreads' request. This is just an acknowledgement, so no body field is required. */ - export interface TerminateThreadsResponse extends Response { - } - - /** Modules request; value of command field is 'modules'. - Modules can be retrieved from the debug adapter with the ModulesRequest which can either return all modules or a range of modules to support paging. - */ - export interface ModulesRequest extends Request { - // command: 'modules'; - arguments: ModulesArguments; - } - - /** Arguments for 'modules' request. */ - export interface ModulesArguments { - /** The index of the first module to return; if omitted modules start at 0. */ - startModule?: number; - /** The number of modules to return. If moduleCount is not specified or 0, all modules are returned. */ - moduleCount?: number; - } - - /** Response to 'modules' request. */ - export interface ModulesResponse extends Response { - body: { - /** All modules or range of modules. */ - modules: Module[]; - /** The total number of modules available. */ - totalModules?: number; - }; - } - - /** LoadedSources request; value of command field is 'loadedSources'. - Retrieves the set of all sources currently loaded by the debugged process. - */ - export interface LoadedSourcesRequest extends Request { - // command: 'loadedSources'; - arguments?: LoadedSourcesArguments; - } - - /** Arguments for 'loadedSources' request. */ - export interface LoadedSourcesArguments { - } - - /** Response to 'loadedSources' request. */ - export interface LoadedSourcesResponse extends Response { - body: { - /** Set of loaded sources. */ - sources: Source[]; - }; - } - - /** Evaluate request; value of command field is 'evaluate'. - Evaluates the given expression in the context of the top most stack frame. - The expression has access to any variables and arguments that are in scope. - */ - export interface EvaluateRequest extends Request { - // command: 'evaluate'; - arguments: EvaluateArguments; - } - - /** Arguments for 'evaluate' request. */ - export interface EvaluateArguments { - /** The expression to evaluate. */ - expression: string; - /** Evaluate the expression in the scope of this stack frame. If not specified, the expression is evaluated in the global scope. */ - frameId?: number; - /** The context in which the evaluate request is run. - Values: - 'watch': evaluate is run in a watch. - 'repl': evaluate is run from REPL console. - 'hover': evaluate is run from a data hover. - etc. - */ - context?: string; - /** Specifies details on how to format the Evaluate result. */ - format?: ValueFormat; - } - - /** Response to 'evaluate' request. */ - export interface EvaluateResponse extends Response { - body: { - /** The result of the evaluate request. */ - result: string; - /** The optional type of the evaluate result. */ - type?: string; - /** Properties of a evaluate result that can be used to determine how to render the result in the UI. */ - presentationHint?: VariablePresentationHint; - /** If variablesReference is > 0, the evaluate result is structured and its children can be retrieved by passing variablesReference to the VariablesRequest. The value should be less than or equal to 2147483647 (2^31 - 1). */ - variablesReference: number; - /** The number of named child variables. - The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1). - */ - namedVariables?: number; - /** The number of indexed child variables. - The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1). - */ - indexedVariables?: number; - /** Memory reference to a location appropriate for this result. For pointer type eval results, this is generally a reference to the memory address contained in the pointer. */ - memoryReference?: string; - }; - } - - /** SetExpression request; value of command field is 'setExpression'. - Evaluates the given 'value' expression and assigns it to the 'expression' which must be a modifiable l-value. - The expressions have access to any variables and arguments that are in scope of the specified frame. - */ - export interface SetExpressionRequest extends Request { - // command: 'setExpression'; - arguments: SetExpressionArguments; - } - - /** Arguments for 'setExpression' request. */ - export interface SetExpressionArguments { - /** The l-value expression to assign to. */ - expression: string; - /** The value expression to assign to the l-value expression. */ - value: string; - /** Evaluate the expressions in the scope of this stack frame. If not specified, the expressions are evaluated in the global scope. */ - frameId?: number; - /** Specifies how the resulting value should be formatted. */ - format?: ValueFormat; - } - - /** Response to 'setExpression' request. */ - export interface SetExpressionResponse extends Response { - body: { - /** The new value of the expression. */ - value: string; - /** The optional type of the value. */ - type?: string; - /** Properties of a value that can be used to determine how to render the result in the UI. */ - presentationHint?: VariablePresentationHint; - /** If variablesReference is > 0, the value is structured and its children can be retrieved by passing variablesReference to the VariablesRequest. The value should be less than or equal to 2147483647 (2^31 - 1). */ - variablesReference?: number; - /** The number of named child variables. - The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1). - */ - namedVariables?: number; - /** The number of indexed child variables. - The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1). - */ - indexedVariables?: number; - }; - } - - /** StepInTargets request; value of command field is 'stepInTargets'. - This request retrieves the possible stepIn targets for the specified stack frame. - These targets can be used in the 'stepIn' request. - The StepInTargets may only be called if the 'supportsStepInTargetsRequest' capability exists and is true. - */ - export interface StepInTargetsRequest extends Request { - // command: 'stepInTargets'; - arguments: StepInTargetsArguments; - } - - /** Arguments for 'stepInTargets' request. */ - export interface StepInTargetsArguments { - /** The stack frame for which to retrieve the possible stepIn targets. */ - frameId: number; - } - - /** Response to 'stepInTargets' request. */ - export interface StepInTargetsResponse extends Response { - body: { - /** The possible stepIn targets of the specified source location. */ - targets: StepInTarget[]; - }; - } - - /** GotoTargets request; value of command field is 'gotoTargets'. - This request retrieves the possible goto targets for the specified source location. - These targets can be used in the 'goto' request. - The GotoTargets request may only be called if the 'supportsGotoTargetsRequest' capability exists and is true. - */ - export interface GotoTargetsRequest extends Request { - // command: 'gotoTargets'; - arguments: GotoTargetsArguments; - } - - /** Arguments for 'gotoTargets' request. */ - export interface GotoTargetsArguments { - /** The source location for which the goto targets are determined. */ - source: Source; - /** The line location for which the goto targets are determined. */ - line: number; - /** An optional column location for which the goto targets are determined. */ - column?: number; - } - - /** Response to 'gotoTargets' request. */ - export interface GotoTargetsResponse extends Response { - body: { - /** The possible goto targets of the specified location. */ - targets: GotoTarget[]; - }; - } - - /** Completions request; value of command field is 'completions'. - Returns a list of possible completions for a given caret position and text. - The CompletionsRequest may only be called if the 'supportsCompletionsRequest' capability exists and is true. - */ - export interface CompletionsRequest extends Request { - // command: 'completions'; - arguments: CompletionsArguments; - } - - /** Arguments for 'completions' request. */ - export interface CompletionsArguments { - /** Returns completions in the scope of this stack frame. If not specified, the completions are returned for the global scope. */ - frameId?: number; - /** One or more source lines. Typically this is the text a user has typed into the debug console before he asked for completion. */ - text: string; - /** The character position for which to determine the completion proposals. */ - column: number; - /** An optional line for which to determine the completion proposals. If missing the first line of the text is assumed. */ - line?: number; - } - - /** Response to 'completions' request. */ - export interface CompletionsResponse extends Response { - body: { - /** The possible completions for . */ - targets: CompletionItem[]; - }; - } - - /** ExceptionInfo request; value of command field is 'exceptionInfo'. - Retrieves the details of the exception that caused this event to be raised. - */ - export interface ExceptionInfoRequest extends Request { - // command: 'exceptionInfo'; - arguments: ExceptionInfoArguments; - } - - /** Arguments for 'exceptionInfo' request. */ - export interface ExceptionInfoArguments { - /** Thread for which exception information should be retrieved. */ - threadId: number; - } - - /** Response to 'exceptionInfo' request. */ - export interface ExceptionInfoResponse extends Response { - body: { - /** ID of the exception that was thrown. */ - exceptionId: string; - /** Descriptive text for the exception provided by the debug adapter. */ - description?: string; - /** Mode that caused the exception notification to be raised. */ - breakMode: ExceptionBreakMode; - /** Detailed information about the exception. */ - details?: ExceptionDetails; - }; - } - - /** ReadMemory request; value of command field is 'readMemory'. - Reads bytes from memory at the provided location. - */ - export interface ReadMemoryRequest extends Request { - // command: 'readMemory'; - arguments: ReadMemoryArguments; - } - - /** Arguments for 'readMemory' request. */ - export interface ReadMemoryArguments { - /** Memory reference to the base location from which data should be read. */ - memoryReference: string; - /** Optional offset (in bytes) to be applied to the reference location before reading data. Can be negative. */ - offset?: number; - /** Number of bytes to read at the specified location and offset. */ - count: number; - } - - /** Response to 'readMemory' request. */ - export interface ReadMemoryResponse extends Response { - body?: { - /** The address of the first byte of data returned. Treated as a hex value if prefixed with '0x', or as a decimal value otherwise. */ - address: string; - /** The number of unreadable bytes encountered after the last successfully read byte. This can be used to determine the number of bytes that must be skipped before a subsequent 'readMemory' request will succeed. */ - unreadableBytes?: number; - /** The bytes read from memory, encoded using base64. */ - data?: string; - }; - } - - /** Disassemble request; value of command field is 'disassemble'. - Disassembles code stored at the provided location. - */ - export interface DisassembleRequest extends Request { - // command: 'disassemble'; - arguments: DisassembleArguments; - } - - /** Arguments for 'disassemble' request. */ - export interface DisassembleArguments { - /** Memory reference to the base location containing the instructions to disassemble. */ - memoryReference: string; - /** Optional offset (in bytes) to be applied to the reference location before disassembling. Can be negative. */ - offset?: number; - /** Optional offset (in instructions) to be applied after the byte offset (if any) before disassembling. Can be negative. */ - instructionOffset?: number; - /** Number of instructions to disassemble starting at the specified location and offset. An adapter must return exactly this number of instructions - any unavailable instructions should be replaced with an implementation-defined 'invalid instruction' value. */ - instructionCount: number; - /** If true, the adapter should attempt to resolve memory addresses and other values to symbolic names. */ - resolveSymbols?: boolean; - } - - /** Response to 'disassemble' request. */ - export interface DisassembleResponse extends Response { - body?: { - /** The list of disassembled instructions. */ - instructions: DisassembledInstruction[]; - }; - } - - /** Information about the capabilities of a debug adapter. */ - export interface Capabilities { - /** The debug adapter supports the 'configurationDone' request. */ - supportsConfigurationDoneRequest?: boolean; - /** The debug adapter supports function breakpoints. */ - supportsFunctionBreakpoints?: boolean; - /** The debug adapter supports conditional breakpoints. */ - supportsConditionalBreakpoints?: boolean; - /** The debug adapter supports breakpoints that break execution after a specified number of hits. */ - supportsHitConditionalBreakpoints?: boolean; - /** The debug adapter supports a (side effect free) evaluate request for data hovers. */ - supportsEvaluateForHovers?: boolean; - /** Available filters or options for the setExceptionBreakpoints request. */ - exceptionBreakpointFilters?: ExceptionBreakpointsFilter[]; - /** The debug adapter supports stepping back via the 'stepBack' and 'reverseContinue' requests. */ - supportsStepBack?: boolean; - /** The debug adapter supports setting a variable to a value. */ - supportsSetVariable?: boolean; - /** The debug adapter supports restarting a frame. */ - supportsRestartFrame?: boolean; - /** The debug adapter supports the 'gotoTargets' request. */ - supportsGotoTargetsRequest?: boolean; - /** The debug adapter supports the 'stepInTargets' request. */ - supportsStepInTargetsRequest?: boolean; - /** The debug adapter supports the 'completions' request. */ - supportsCompletionsRequest?: boolean; - /** The set of characters that should trigger completion in a REPL. If not specified, the UI should assume the '.' character. */ - completionTriggerCharacters?: string[]; - /** The debug adapter supports the 'modules' request. */ - supportsModulesRequest?: boolean; - /** The set of additional module information exposed by the debug adapter. */ - additionalModuleColumns?: ColumnDescriptor[]; - /** Checksum algorithms supported by the debug adapter. */ - supportedChecksumAlgorithms?: ChecksumAlgorithm[]; - /** The debug adapter supports the 'restart' request. In this case a client should not implement 'restart' by terminating and relaunching the adapter but by calling the RestartRequest. */ - supportsRestartRequest?: boolean; - /** The debug adapter supports 'exceptionOptions' on the setExceptionBreakpoints request. */ - supportsExceptionOptions?: boolean; - /** The debug adapter supports a 'format' attribute on the stackTraceRequest, variablesRequest, and evaluateRequest. */ - supportsValueFormattingOptions?: boolean; - /** The debug adapter supports the 'exceptionInfo' request. */ - supportsExceptionInfoRequest?: boolean; - /** The debug adapter supports the 'terminateDebuggee' attribute on the 'disconnect' request. */ - supportTerminateDebuggee?: boolean; - /** The debug adapter supports the delayed loading of parts of the stack, which requires that both the 'startFrame' and 'levels' arguments and the 'totalFrames' result of the 'StackTrace' request are supported. */ - supportsDelayedStackTraceLoading?: boolean; - /** The debug adapter supports the 'loadedSources' request. */ - supportsLoadedSourcesRequest?: boolean; - /** The debug adapter supports logpoints by interpreting the 'logMessage' attribute of the SourceBreakpoint. */ - supportsLogPoints?: boolean; - /** The debug adapter supports the 'terminateThreads' request. */ - supportsTerminateThreadsRequest?: boolean; - /** The debug adapter supports the 'setExpression' request. */ - supportsSetExpression?: boolean; - /** The debug adapter supports the 'terminate' request. */ - supportsTerminateRequest?: boolean; - /** The debug adapter supports data breakpoints. */ - supportsDataBreakpoints?: boolean; - /** The debug adapter supports the 'readMemory' request. */ - supportsReadMemoryRequest?: boolean; - /** The debug adapter supports the 'disassemble' request. */ - supportsDisassembleRequest?: boolean; - /** The debug adapter supports the 'cancel' request. */ - supportsCancelRequest?: boolean; - /** The debug adapter supports the 'breakpointLocations' request. */ - supportsBreakpointLocationsRequest?: boolean; - } - - /** An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with. */ - export interface ExceptionBreakpointsFilter { - /** The internal ID of the filter. This value is passed to the setExceptionBreakpoints request. */ - filter: string; - /** The name of the filter. This will be shown in the UI. */ - label: string; - /** Initial value of the filter. If not specified a value 'false' is assumed. */ - default?: boolean; - } - - /** A structured message object. Used to return errors from requests. */ - export interface Message { - /** Unique identifier for the message. */ - id: number; - /** A format string for the message. Embedded variables have the form '{name}'. - If variable name starts with an underscore character, the variable does not contain user data (PII) and can be safely used for telemetry purposes. - */ - format: string; - /** An object used as a dictionary for looking up the variables in the format string. */ - variables?: { [key: string]: string; }; - /** If true send to telemetry. */ - sendTelemetry?: boolean; - /** If true show user. */ - showUser?: boolean; - /** An optional url where additional information about this message can be found. */ - url?: string; - /** An optional label that is presented to the user as the UI for opening the url. */ - urlLabel?: string; - } - - /** A Module object represents a row in the modules view. - Two attributes are mandatory: an id identifies a module in the modules view and is used in a ModuleEvent for identifying a module for adding, updating or deleting. - The name is used to minimally render the module in the UI. - - Additional attributes can be added to the module. They will show up in the module View if they have a corresponding ColumnDescriptor. - - To avoid an unnecessary proliferation of additional attributes with similar semantics but different names - we recommend to re-use attributes from the 'recommended' list below first, and only introduce new attributes if nothing appropriate could be found. - */ - export interface Module { - /** Unique identifier for the module. */ - id: number | string; - /** A name of the module. */ - name: string; - /** optional but recommended attributes. - always try to use these first before introducing additional attributes. - - Logical full path to the module. The exact definition is implementation defined, but usually this would be a full path to the on-disk file for the module. - */ - path?: string; - /** True if the module is optimized. */ - isOptimized?: boolean; - /** True if the module is considered 'user code' by a debugger that supports 'Just My Code'. */ - isUserCode?: boolean; - /** Version of Module. */ - version?: string; - /** User understandable description of if symbols were found for the module (ex: 'Symbols Loaded', 'Symbols not found', etc. */ - symbolStatus?: string; - /** Logical full path to the symbol file. The exact definition is implementation defined. */ - symbolFilePath?: string; - /** Module created or modified. */ - dateTimeStamp?: string; - /** Address range covered by this module. */ - addressRange?: string; - } - - /** A ColumnDescriptor specifies what module attribute to show in a column of the ModulesView, how to format it, and what the column's label should be. - It is only used if the underlying UI actually supports this level of customization. - */ - export interface ColumnDescriptor { - /** Name of the attribute rendered in this column. */ - attributeName: string; - /** Header UI label of column. */ - label: string; - /** Format to use for the rendered values in this column. TBD how the format strings looks like. */ - format?: string; - /** Datatype of values in this column. Defaults to 'string' if not specified. */ - type?: 'string' | 'number' | 'boolean' | 'unixTimestampUTC'; - /** Width of this column in characters (hint only). */ - width?: number; - } - - /** The ModulesViewDescriptor is the container for all declarative configuration options of a ModuleView. - For now it only specifies the columns to be shown in the modules view. - */ - export interface ModulesViewDescriptor { - columns: ColumnDescriptor[]; - } - - /** A Thread */ - export interface Thread { - /** Unique identifier for the thread. */ - id: number; - /** A name of the thread. */ - name: string; - } - - /** A Source is a descriptor for source code. It is returned from the debug adapter as part of a StackFrame and it is used by clients when specifying breakpoints. */ - export interface Source { - /** The short name of the source. Every source returned from the debug adapter has a name. When sending a source to the debug adapter this name is optional. */ - name?: string; - /** The path of the source to be shown in the UI. It is only used to locate and load the content of the source if no sourceReference is specified (or its value is 0). */ - path?: string; - /** If sourceReference > 0 the contents of the source must be retrieved through the SourceRequest (even if a path is specified). A sourceReference is only valid for a session, so it must not be used to persist a source. The value should be less than or equal to 2147483647 (2^31 - 1). */ - sourceReference?: number; - /** An optional hint for how to present the source in the UI. A value of 'deemphasize' can be used to indicate that the source is not available or that it is skipped on stepping. */ - presentationHint?: 'normal' | 'emphasize' | 'deemphasize'; - /** The (optional) origin of this source: possible values 'internal module', 'inlined content from source map', etc. */ - origin?: string; - /** An optional list of sources that are related to this source. These may be the source that generated this source. */ - sources?: Source[]; - /** Optional data that a debug adapter might want to loop through the client. The client should leave the data intact and persist it across sessions. The client should not interpret the data. */ - adapterData?: any; - /** The checksums associated with this file. */ - checksums?: Checksum[]; - } - - /** A Stackframe contains the source location. */ - export interface StackFrame { - /** An identifier for the stack frame. It must be unique across all threads. This id can be used to retrieve the scopes of the frame with the 'scopesRequest' or to restart the execution of a stackframe. */ - id: number; - /** The name of the stack frame, typically a method name. */ - name: string; - /** The optional source of the frame. */ - source?: Source; - /** The line within the file of the frame. If source is null or doesn't exist, line is 0 and must be ignored. */ - line: number; - /** The column within the line. If source is null or doesn't exist, column is 0 and must be ignored. */ - column: number; - /** An optional end line of the range covered by the stack frame. */ - endLine?: number; - /** An optional end column of the range covered by the stack frame. */ - endColumn?: number; - /** Optional memory reference for the current instruction pointer in this frame. */ - instructionPointerReference?: string; - /** The module associated with this frame, if any. */ - moduleId?: number | string; - /** An optional hint for how to present this frame in the UI. A value of 'label' can be used to indicate that the frame is an artificial frame that is used as a visual label or separator. A value of 'subtle' can be used to change the appearance of a frame in a 'subtle' way. */ - presentationHint?: 'normal' | 'label' | 'subtle'; - } - - /** A Scope is a named container for variables. Optionally a scope can map to a source or a range within a source. */ - export interface Scope { - /** Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This string is shown in the UI as is and can be translated. */ - name: string; - /** An optional hint for how to present this scope in the UI. If this attribute is missing, the scope is shown with a generic UI. - Values: - 'arguments': Scope contains method arguments. - 'locals': Scope contains local variables. - 'registers': Scope contains registers. Only a single 'registers' scope should be returned from a 'scopes' request. - etc. - */ - presentationHint?: string; - /** The variables of this scope can be retrieved by passing the value of variablesReference to the VariablesRequest. */ - variablesReference: number; - /** The number of named variables in this scope. - The client can use this optional information to present the variables in a paged UI and fetch them in chunks. - */ - namedVariables?: number; - /** The number of indexed variables in this scope. - The client can use this optional information to present the variables in a paged UI and fetch them in chunks. - */ - indexedVariables?: number; - /** If true, the number of variables in this scope is large or expensive to retrieve. */ - expensive: boolean; - /** Optional source for this scope. */ - source?: Source; - /** Optional start line of the range covered by this scope. */ - line?: number; - /** Optional start column of the range covered by this scope. */ - column?: number; - /** Optional end line of the range covered by this scope. */ - endLine?: number; - /** Optional end column of the range covered by this scope. */ - endColumn?: number; - } - - /** A Variable is a name/value pair. - Optionally a variable can have a 'type' that is shown if space permits or when hovering over the variable's name. - An optional 'kind' is used to render additional properties of the variable, e.g. different icons can be used to indicate that a variable is public or private. - If the value is structured (has children), a handle is provided to retrieve the children with the VariablesRequest. - If the number of named or indexed children is large, the numbers should be returned via the optional 'namedVariables' and 'indexedVariables' attributes. - The client can use this optional information to present the children in a paged UI and fetch them in chunks. - */ - export interface Variable { - /** The variable's name. */ - name: string; - /** The variable's value. This can be a multi-line text, e.g. for a function the body of a function. */ - value: string; - /** The type of the variable's value. Typically shown in the UI when hovering over the value. */ - type?: string; - /** Properties of a variable that can be used to determine how to render the variable in the UI. */ - presentationHint?: VariablePresentationHint; - /** Optional evaluatable name of this variable which can be passed to the 'EvaluateRequest' to fetch the variable's value. */ - evaluateName?: string; - /** If variablesReference is > 0, the variable is structured and its children can be retrieved by passing variablesReference to the VariablesRequest. */ - variablesReference: number; - /** The number of named child variables. - The client can use this optional information to present the children in a paged UI and fetch them in chunks. - */ - namedVariables?: number; - /** The number of indexed child variables. - The client can use this optional information to present the children in a paged UI and fetch them in chunks. - */ - indexedVariables?: number; - /** Optional memory reference for the variable if the variable represents executable code, such as a function pointer. */ - memoryReference?: string; - } - - /** Optional properties of a variable that can be used to determine how to render the variable in the UI. */ - export interface VariablePresentationHint { - /** The kind of variable. Before introducing additional values, try to use the listed values. - Values: - 'property': Indicates that the object is a property. - 'method': Indicates that the object is a method. - 'class': Indicates that the object is a class. - 'data': Indicates that the object is data. - 'event': Indicates that the object is an event. - 'baseClass': Indicates that the object is a base class. - 'innerClass': Indicates that the object is an inner class. - 'interface': Indicates that the object is an interface. - 'mostDerivedClass': Indicates that the object is the most derived class. - 'virtual': Indicates that the object is virtual, that means it is a synthetic object introduced by the adapter for rendering purposes, e.g. an index range for large arrays. - 'dataBreakpoint': Indicates that a data breakpoint is registered for the object. - etc. - */ - kind?: string; - /** Set of attributes represented as an array of strings. Before introducing additional values, try to use the listed values. - Values: - 'static': Indicates that the object is static. - 'constant': Indicates that the object is a constant. - 'readOnly': Indicates that the object is read only. - 'rawString': Indicates that the object is a raw string. - 'hasObjectId': Indicates that the object can have an Object ID created for it. - 'canHaveObjectId': Indicates that the object has an Object ID associated with it. - 'hasSideEffects': Indicates that the evaluation had side effects. - etc. - */ - attributes?: string[]; - /** Visibility of variable. Before introducing additional values, try to use the listed values. - Values: 'public', 'private', 'protected', 'internal', 'final', etc. - */ - visibility?: string; - } - - /** Properties of a breakpoint location returned from the 'breakpointLocations' request. */ - export interface BreakpointLocation { - /** Start line of breakpoint location. */ - line: number; - /** Optional start column of breakpoint location. */ - column?: number; - /** Optional end line of breakpoint location if the location covers a range. */ - endLine?: number; - /** Optional end column of breakpoint location if the location covers a range. */ - endColumn?: number; - } - - /** Properties of a breakpoint or logpoint passed to the setBreakpoints request. */ - export interface SourceBreakpoint { - /** The source line of the breakpoint or logpoint. */ - line: number; - /** An optional source column of the breakpoint. */ - column?: number; - /** An optional expression for conditional breakpoints. */ - condition?: string; - /** An optional expression that controls how many hits of the breakpoint are ignored. The backend is expected to interpret the expression as needed. */ - hitCondition?: string; - /** If this attribute exists and is non-empty, the backend must not 'break' (stop) but log the message instead. Expressions within {} are interpolated. */ - logMessage?: string; - } - - /** Properties of a breakpoint passed to the setFunctionBreakpoints request. */ - export interface FunctionBreakpoint { - /** The name of the function. */ - name: string; - /** An optional expression for conditional breakpoints. */ - condition?: string; - /** An optional expression that controls how many hits of the breakpoint are ignored. The backend is expected to interpret the expression as needed. */ - hitCondition?: string; - } - - /** This enumeration defines all possible access types for data breakpoints. */ - export type DataBreakpointAccessType = 'read' | 'write' | 'readWrite'; - - /** Properties of a data breakpoint passed to the setDataBreakpoints request. */ - export interface DataBreakpoint { - /** An id representing the data. This id is returned from the dataBreakpointInfo request. */ - dataId: string; - /** The access type of the data. */ - accessType?: DataBreakpointAccessType; - /** An optional expression for conditional breakpoints. */ - condition?: string; - /** An optional expression that controls how many hits of the breakpoint are ignored. The backend is expected to interpret the expression as needed. */ - hitCondition?: string; - } - - /** Information about a Breakpoint created in setBreakpoints or setFunctionBreakpoints. */ - export interface Breakpoint { - /** An optional identifier for the breakpoint. It is needed if breakpoint events are used to update or remove breakpoints. */ - id?: number; - /** If true breakpoint could be set (but not necessarily at the desired location). */ - verified: boolean; - /** An optional message about the state of the breakpoint. This is shown to the user and can be used to explain why a breakpoint could not be verified. */ - message?: string; - /** The source where the breakpoint is located. */ - source?: Source; - /** The start line of the actual range covered by the breakpoint. */ - line?: number; - /** An optional start column of the actual range covered by the breakpoint. */ - column?: number; - /** An optional end line of the actual range covered by the breakpoint. */ - endLine?: number; - /** An optional end column of the actual range covered by the breakpoint. If no end line is given, then the end column is assumed to be in the start line. */ - endColumn?: number; - } - - /** A StepInTarget can be used in the 'stepIn' request and determines into which single target the stepIn request should step. */ - export interface StepInTarget { - /** Unique identifier for a stepIn target. */ - id: number; - /** The name of the stepIn target (shown in the UI). */ - label: string; - } - - /** A GotoTarget describes a code location that can be used as a target in the 'goto' request. - The possible goto targets can be determined via the 'gotoTargets' request. - */ - export interface GotoTarget { - /** Unique identifier for a goto target. This is used in the goto request. */ - id: number; - /** The name of the goto target (shown in the UI). */ - label: string; - /** The line of the goto target. */ - line: number; - /** An optional column of the goto target. */ - column?: number; - /** An optional end line of the range covered by the goto target. */ - endLine?: number; - /** An optional end column of the range covered by the goto target. */ - endColumn?: number; - /** Optional memory reference for the instruction pointer value represented by this target. */ - instructionPointerReference?: string; - } - - /** CompletionItems are the suggestions returned from the CompletionsRequest. */ - export interface CompletionItem { - /** The label of this completion item. By default this is also the text that is inserted when selecting this completion. */ - label: string; - /** If text is not falsy then it is inserted instead of the label. */ - text?: string; - /** A string that should be used when comparing this item with other items. When `falsy` the label is used. */ - sortText?: string; - /** The item's type. Typically the client uses this information to render the item in the UI with an icon. */ - type?: CompletionItemType; - /** This value determines the location (in the CompletionsRequest's 'text' attribute) where the completion text is added. - If missing the text is added at the location specified by the CompletionsRequest's 'column' attribute. - */ - start?: number; - /** This value determines how many characters are overwritten by the completion text. - If missing the value 0 is assumed which results in the completion text being inserted. - */ - length?: number; - } - - /** Some predefined types for the CompletionItem. Please note that not all clients have specific icons for all of them. */ - export type CompletionItemType = 'method' | 'function' | 'constructor' | 'field' | 'variable' | 'class' | 'interface' | 'module' | 'property' | 'unit' | 'value' | 'enum' | 'keyword' | 'snippet' | 'text' | 'color' | 'file' | 'reference' | 'customcolor'; - - /** Names of checksum algorithms that may be supported by a debug adapter. */ - export type ChecksumAlgorithm = 'MD5' | 'SHA1' | 'SHA256' | 'timestamp'; - - /** The checksum of an item calculated by the specified algorithm. */ - export interface Checksum { - /** The algorithm used to calculate this checksum. */ - algorithm: ChecksumAlgorithm; - /** Value of the checksum. */ - checksum: string; - } - - /** Provides formatting information for a value. */ - export interface ValueFormat { - /** Display the value in hex. */ - hex?: boolean; - } - - /** Provides formatting information for a stack frame. */ - export interface StackFrameFormat extends ValueFormat { - /** Displays parameters for the stack frame. */ - parameters?: boolean; - /** Displays the types of parameters for the stack frame. */ - parameterTypes?: boolean; - /** Displays the names of parameters for the stack frame. */ - parameterNames?: boolean; - /** Displays the values of parameters for the stack frame. */ - parameterValues?: boolean; - /** Displays the line number of the stack frame. */ - line?: boolean; - /** Displays the module of the stack frame. */ - module?: boolean; - /** Includes all stack frames, including those the debug adapter might otherwise hide. */ - includeAll?: boolean; - } - - /** An ExceptionOptions assigns configuration options to a set of exceptions. */ - export interface ExceptionOptions { - /** A path that selects a single or multiple exceptions in a tree. If 'path' is missing, the whole tree is selected. By convention the first segment of the path is a category that is used to group exceptions in the UI. */ - path?: ExceptionPathSegment[]; - /** Condition when a thrown exception should result in a break. */ - breakMode: ExceptionBreakMode; - } - - /** This enumeration defines all possible conditions when a thrown exception should result in a break. - never: never breaks, - always: always breaks, - unhandled: breaks when exception unhandled, - userUnhandled: breaks if the exception is not handled by user code. - */ - export type ExceptionBreakMode = 'never' | 'always' | 'unhandled' | 'userUnhandled'; - - /** An ExceptionPathSegment represents a segment in a path that is used to match leafs or nodes in a tree of exceptions. If a segment consists of more than one name, it matches the names provided if 'negate' is false or missing or it matches anything except the names provided if 'negate' is true. */ - export interface ExceptionPathSegment { - /** If false or missing this segment matches the names provided, otherwise it matches anything except the names provided. */ - negate?: boolean; - /** Depending on the value of 'negate' the names that should match or not match. */ - names: string[]; - } - - /** Detailed information about an exception that has occurred. */ - export interface ExceptionDetails { - /** Message contained in the exception. */ - message?: string; - /** Short type name of the exception object. */ - typeName?: string; - /** Fully-qualified type name of the exception object. */ - fullTypeName?: string; - /** Optional expression that can be evaluated in the current scope to obtain the exception object. */ - evaluateName?: string; - /** Stack trace at the time the exception was thrown. */ - stackTrace?: string; - /** Details of the exception contained by this exception, if any. */ - innerException?: ExceptionDetails[]; - } - - /** Represents a single disassembled instruction. */ - export interface DisassembledInstruction { - /** The address of the instruction. Treated as a hex value if prefixed with '0x', or as a decimal value otherwise. */ - address: string; - /** Optional raw bytes representing the instruction and its operands, in an implementation-defined format. */ - instructionBytes?: string; - /** Text representing the instruction and its operands, in an implementation-defined format. */ - instruction: string; - /** Name of the symbol that corresponds with the location of this instruction, if any. */ - symbol?: string; - /** Source location that corresponds to this instruction, if any. Should always be set (if available) on the first instruction returned, but can be omitted afterwards if this instruction maps to the same source file as the previous instruction. */ - location?: Source; - /** The line within the source location that corresponds to this instruction, if any. */ - line?: number; - /** The column within the line that corresponds to this instruction, if any. */ - column?: number; - /** The end line of the range that corresponds to this instruction, if any. */ - endLine?: number; - /** The end column of the range that corresponds to this instruction, if any. */ - endColumn?: number; - } -} - -//------------------------------------------------------------------------------------------------------------------------------ - -export class Message implements DebugProtocol.ProtocolMessage { - seq: number; - type: string; - - public constructor(type: string) { - this.seq = 0; - this.type = type; - } -} - -export class Response extends Message implements DebugProtocol.Response { - request_seq: number; - success: boolean; - command: string; - - public constructor(request: DebugProtocol.Request, message?: string) { - super('response'); - this.request_seq = request.seq; - this.command = request.command; - if (message) { - this.success = false; - (this).message = message; - } else { - this.success = true; - } - } -} - -export class Event extends Message implements DebugProtocol.Event { - event: string; - - public constructor(event: string, body?: any) { - super('event'); - this.event = event; - if (body) { - (this).body = body; - } - } -} - -//-------------------------------------------------------------------------------------------------------------------------------- - -export class ProtocolServer implements vscode.DebugAdapter { - - private close = new vscode.EventEmitter(); - onClose: vscode.Event = this.close.event; - - private error = new vscode.EventEmitter(); - onError: vscode.Event = this.error.event; - - private sendMessage = new vscode.EventEmitter(); - readonly onDidSendMessage: vscode.Event = this.sendMessage.event; - - private _sequence: number = 1; - private _pendingRequests = new Map void>(); - - - public handleMessage(message: DebugProtocol.ProtocolMessage): void { - this.dispatch(message); - } - - public dispose() { - } - - public sendEvent(event: DebugProtocol.Event): void { - this._send('event', event); - } - - public sendResponse(response: DebugProtocol.Response): void { - if (response.seq > 0) { - console.error(`attempt to send more than one response for command ${response.command}`); - } else { - this._send('response', response); - } - } - - public sendRequest(command: string, args: any, timeout: number, cb: (response: DebugProtocol.Response) => void): void { - - const request: any = { - command: command - }; - if (args && Object.keys(args).length > 0) { - request.arguments = args; - } - - this._send('request', request); - - if (cb) { - this._pendingRequests.set(request.seq, cb); - - const timer = setTimeout(() => { - clearTimeout(timer); - const clb = this._pendingRequests.get(request.seq); - if (clb) { - this._pendingRequests.delete(request.seq); - clb(new Response(request, 'timeout')); - } - }, timeout); - } - } - - // ---- protected ---------------------------------------------------------- - - protected dispatchRequest(_request: DebugProtocol.Request): void { - } - - // ---- private ------------------------------------------------------------ - - private dispatch(msg: DebugProtocol.ProtocolMessage) { - if (msg.type === 'request') { - this.dispatchRequest(msg); - } else if (msg.type === 'response') { - const response = msg; - const clb = this._pendingRequests.get(response.request_seq); - if (clb) { - this._pendingRequests.delete(response.request_seq); - clb(response); - } - } - } - - private _send(typ: 'request' | 'response' | 'event', message: DebugProtocol.ProtocolMessage): void { - - message.type = typ; - message.seq = this._sequence++; - - this.sendMessage.fire(message); - } -} - -//------------------------------------------------------------------------------------------------------------------------------- - -export class Source implements DebugProtocol.Source { - name: string; - path?: string; - sourceReference: number; - - public constructor(name: string, path?: string, id: number = 0, origin?: string, data?: any) { - this.name = name; - this.path = path; - this.sourceReference = id; - if (origin) { - (this).origin = origin; - } - if (data) { - (this).adapterData = data; - } - } -} - -export class Scope implements DebugProtocol.Scope { - name: string; - variablesReference: number; - expensive: boolean; - - public constructor(name: string, reference: number, expensive: boolean = false) { - this.name = name; - this.variablesReference = reference; - this.expensive = expensive; - } -} - -export class StackFrame implements DebugProtocol.StackFrame { - id: number; - source?: Source; - line: number; - column: number; - name: string; - - public constructor(i: number, nm: string, src?: Source, ln: number = 0, col: number = 0) { - this.id = i; - this.source = src; - this.line = ln; - this.column = col; - this.name = nm; - } -} - -export class Thread implements DebugProtocol.Thread { - id: number; - name: string; - - public constructor(id: number, name: string) { - this.id = id; - if (name) { - this.name = name; - } else { - this.name = 'Thread #' + id; - } - } -} - -export class Variable implements DebugProtocol.Variable { - name: string; - value: string; - variablesReference: number; - - public constructor(name: string, value: string, ref: number = 0, indexedVariables?: number, namedVariables?: number) { - this.name = name; - this.value = value; - this.variablesReference = ref; - if (typeof namedVariables === 'number') { - (this).namedVariables = namedVariables; - } - if (typeof indexedVariables === 'number') { - (this).indexedVariables = indexedVariables; - } - } -} - -export class Breakpoint implements DebugProtocol.Breakpoint { - verified: boolean; - - public constructor(verified: boolean, line?: number, column?: number, source?: Source) { - this.verified = verified; - const e: DebugProtocol.Breakpoint = this; - if (typeof line === 'number') { - e.line = line; - } - if (typeof column === 'number') { - e.column = column; - } - if (source) { - e.source = source; - } - } -} - -export class Module implements DebugProtocol.Module { - id: number | string; - name: string; - - public constructor(id: number | string, name: string) { - this.id = id; - this.name = name; - } -} - -export class CompletionItem implements DebugProtocol.CompletionItem { - label: string; - start: number; - length: number; - - public constructor(label: string, start: number, length: number = 0) { - this.label = label; - this.start = start; - this.length = length; - } -} - -export class StoppedEvent extends Event implements DebugProtocol.StoppedEvent { - body: { - reason: string; - }; - - public constructor(reason: string, threadId?: number, exceptionText?: string) { - super('stopped'); - this.body = { - reason: reason - }; - if (typeof threadId === 'number') { - (this as DebugProtocol.StoppedEvent).body.threadId = threadId; - } - if (typeof exceptionText === 'string') { - (this as DebugProtocol.StoppedEvent).body.text = exceptionText; - } - } -} - -export class ContinuedEvent extends Event implements DebugProtocol.ContinuedEvent { - body: { - threadId: number; - }; - - public constructor(threadId: number, allThreadsContinued?: boolean) { - super('continued'); - this.body = { - threadId: threadId - }; - - if (typeof allThreadsContinued === 'boolean') { - (this).body.allThreadsContinued = allThreadsContinued; - } - } -} - -export class InitializedEvent extends Event implements DebugProtocol.InitializedEvent { - public constructor() { - super('initialized'); - } -} - -export class TerminatedEvent extends Event implements DebugProtocol.TerminatedEvent { - public constructor(restart?: any) { - super('terminated'); - if (typeof restart === 'boolean' || restart) { - const e: DebugProtocol.TerminatedEvent = this; - e.body = { - restart: restart - }; - } - } -} - -export class OutputEvent extends Event implements DebugProtocol.OutputEvent { - body: { - category: string, - output: string, - data?: any - }; - - public constructor(output: string, category: string = 'console', data?: any) { - super('output'); - this.body = { - category: category, - output: output - }; - if (data !== undefined) { - this.body.data = data; - } - } -} - -export class ThreadEvent extends Event implements DebugProtocol.ThreadEvent { - body: { - reason: string, - threadId: number - }; - - public constructor(reason: string, threadId: number) { - super('thread'); - this.body = { - reason: reason, - threadId: threadId - }; - } -} - -export class BreakpointEvent extends Event implements DebugProtocol.BreakpointEvent { - body: { - reason: string, - breakpoint: Breakpoint - }; - - public constructor(reason: string, breakpoint: Breakpoint) { - super('breakpoint'); - this.body = { - reason: reason, - breakpoint: breakpoint - }; - } -} - -export class ModuleEvent extends Event implements DebugProtocol.ModuleEvent { - body: { - reason: 'new' | 'changed' | 'removed', - module: Module - }; - - public constructor(reason: 'new' | 'changed' | 'removed', module: Module) { - super('module'); - this.body = { - reason: reason, - module: module - }; - } -} - -export class LoadedSourceEvent extends Event implements DebugProtocol.LoadedSourceEvent { - body: { - reason: 'new' | 'changed' | 'removed', - source: Source - }; - - public constructor(reason: 'new' | 'changed' | 'removed', source: Source) { - super('loadedSource'); - this.body = { - reason: reason, - source: source - }; - } -} - -export class CapabilitiesEvent extends Event implements DebugProtocol.CapabilitiesEvent { - body: { - capabilities: DebugProtocol.Capabilities - }; - - public constructor(capabilities: DebugProtocol.Capabilities) { - super('capabilities'); - this.body = { - capabilities: capabilities - }; - } -} - -export enum ErrorDestination { - User = 1, - Telemetry = 2 -} - -export class DebugSession extends ProtocolServer { - - private _debuggerLinesStartAt1: boolean; - private _debuggerColumnsStartAt1: boolean; - private _debuggerPathsAreURIs: boolean; - - private _clientLinesStartAt1: boolean; - private _clientColumnsStartAt1: boolean; - private _clientPathsAreURIs: boolean; - - protected _isServer: boolean; - - public constructor(obsolete_debuggerLinesAndColumnsStartAt1?: boolean, obsolete_isServer?: boolean) { - super(); - - const linesAndColumnsStartAt1 = typeof obsolete_debuggerLinesAndColumnsStartAt1 === 'boolean' ? obsolete_debuggerLinesAndColumnsStartAt1 : false; - this._debuggerLinesStartAt1 = linesAndColumnsStartAt1; - this._debuggerColumnsStartAt1 = linesAndColumnsStartAt1; - this._debuggerPathsAreURIs = false; - - this._clientLinesStartAt1 = true; - this._clientColumnsStartAt1 = true; - this._clientPathsAreURIs = false; - - this._isServer = typeof obsolete_isServer === 'boolean' ? obsolete_isServer : false; - - this.onClose(() => { - this.shutdown(); - }); - this.onError((_error) => { - this.shutdown(); - }); - } - - public setDebuggerPathFormat(format: string) { - this._debuggerPathsAreURIs = format !== 'path'; - } - - public setDebuggerLinesStartAt1(enable: boolean) { - this._debuggerLinesStartAt1 = enable; - } - - public setDebuggerColumnsStartAt1(enable: boolean) { - this._debuggerColumnsStartAt1 = enable; - } - - public setRunAsServer(enable: boolean) { - this._isServer = enable; - } - - public shutdown(): void { - if (this._isServer) { - // shutdown ignored in server mode - } else { - // TODO@AW - /* - // wait a bit before shutting down - setTimeout(() => { - process.exit(0); - }, 100); - */ - } - } - - protected sendErrorResponse(response: DebugProtocol.Response, codeOrMessage: number | DebugProtocol.Message, format?: string, variables?: any, dest: ErrorDestination = ErrorDestination.User): void { - - let msg: DebugProtocol.Message; - if (typeof codeOrMessage === 'number') { - msg = { - id: codeOrMessage, - format: format - }; - if (variables) { - msg.variables = variables; - } - if (dest & ErrorDestination.User) { - msg.showUser = true; - } - if (dest & ErrorDestination.Telemetry) { - msg.sendTelemetry = true; - } - } else { - msg = codeOrMessage; - } - - response.success = false; - response.message = DebugSession.formatPII(msg.format, true, msg.variables); - if (!response.body) { - response.body = {}; - } - response.body.error = msg; - - this.sendResponse(response); - } - - public runInTerminalRequest(args: DebugProtocol.RunInTerminalRequestArguments, timeout: number, cb: (response: DebugProtocol.Response) => void) { - this.sendRequest('runInTerminal', args, timeout, cb); - } - - protected dispatchRequest(request: DebugProtocol.Request): void { - - const response = new Response(request); - - try { - if (request.command === 'initialize') { - const args = request.arguments; - - if (typeof args.linesStartAt1 === 'boolean') { - this._clientLinesStartAt1 = args.linesStartAt1; - } - if (typeof args.columnsStartAt1 === 'boolean') { - this._clientColumnsStartAt1 = args.columnsStartAt1; - } - - if (args.pathFormat !== 'path') { - this.sendErrorResponse(response, 2018, 'debug adapter only supports native paths', null, ErrorDestination.Telemetry); - } else { - const initializeResponse = response; - initializeResponse.body = {}; - this.initializeRequest(initializeResponse, args); - } - - } else if (request.command === 'launch') { - this.launchRequest(response, request.arguments, request); - - } else if (request.command === 'attach') { - this.attachRequest(response, request.arguments, request); - - } else if (request.command === 'disconnect') { - this.disconnectRequest(response, request.arguments, request); - - } else if (request.command === 'terminate') { - this.terminateRequest(response, request.arguments, request); - - } else if (request.command === 'restart') { - this.restartRequest(response, request.arguments, request); - - } else if (request.command === 'setBreakpoints') { - this.setBreakPointsRequest(response, request.arguments, request); - - } else if (request.command === 'setFunctionBreakpoints') { - this.setFunctionBreakPointsRequest(response, request.arguments, request); - - } else if (request.command === 'setExceptionBreakpoints') { - this.setExceptionBreakPointsRequest(response, request.arguments, request); - - } else if (request.command === 'configurationDone') { - this.configurationDoneRequest(response, request.arguments, request); - - } else if (request.command === 'continue') { - this.continueRequest(response, request.arguments, request); - - } else if (request.command === 'next') { - this.nextRequest(response, request.arguments, request); - - } else if (request.command === 'stepIn') { - this.stepInRequest(response, request.arguments, request); - - } else if (request.command === 'stepOut') { - this.stepOutRequest(response, request.arguments, request); - - } else if (request.command === 'stepBack') { - this.stepBackRequest(response, request.arguments, request); - - } else if (request.command === 'reverseContinue') { - this.reverseContinueRequest(response, request.arguments, request); - - } else if (request.command === 'restartFrame') { - this.restartFrameRequest(response, request.arguments, request); - - } else if (request.command === 'goto') { - this.gotoRequest(response, request.arguments, request); - - } else if (request.command === 'pause') { - this.pauseRequest(response, request.arguments, request); - - } else if (request.command === 'stackTrace') { - this.stackTraceRequest(response, request.arguments, request); - - } else if (request.command === 'scopes') { - this.scopesRequest(response, request.arguments, request); - - } else if (request.command === 'variables') { - this.variablesRequest(response, request.arguments, request); - - } else if (request.command === 'setVariable') { - this.setVariableRequest(response, request.arguments, request); - - } else if (request.command === 'setExpression') { - this.setExpressionRequest(response, request.arguments, request); - - } else if (request.command === 'source') { - this.sourceRequest(response, request.arguments, request); - - } else if (request.command === 'threads') { - this.threadsRequest(response, request); - - } else if (request.command === 'terminateThreads') { - this.terminateThreadsRequest(response, request.arguments, request); - - } else if (request.command === 'evaluate') { - this.evaluateRequest(response, request.arguments, request); - - } else if (request.command === 'stepInTargets') { - this.stepInTargetsRequest(response, request.arguments, request); - - } else if (request.command === 'gotoTargets') { - this.gotoTargetsRequest(response, request.arguments, request); - - } else if (request.command === 'completions') { - this.completionsRequest(response, request.arguments, request); - - } else if (request.command === 'exceptionInfo') { - this.exceptionInfoRequest(response, request.arguments, request); - - } else if (request.command === 'loadedSources') { - this.loadedSourcesRequest(response, request.arguments, request); - - } else if (request.command === 'dataBreakpointInfo') { - this.dataBreakpointInfoRequest(response, request.arguments, request); - - } else if (request.command === 'setDataBreakpoints') { - this.setDataBreakpointsRequest(response, request.arguments, request); - - } else if (request.command === 'readMemory') { - this.readMemoryRequest(response, request.arguments, request); - - } else if (request.command === 'disassemble') { - this.disassembleRequest(response, request.arguments, request); - - } else if (request.command === 'cancel') { - this.cancelRequest(response, request.arguments, request); - - } else if (request.command === 'breakpointLocations') { - this.breakpointLocationsRequest(response, request.arguments, request); - - } else { - this.customRequest(request.command, response, request.arguments, request); - } - } catch (e) { - this.sendErrorResponse(response, 1104, '{_stack}', { _exception: e.message, _stack: e.stack }, ErrorDestination.Telemetry); - } - } - - protected initializeRequest(response: DebugProtocol.InitializeResponse, _args: DebugProtocol.InitializeRequestArguments): void { - - response.body = response.body || {}; - - // This default debug adapter does not support conditional breakpoints. - response.body.supportsConditionalBreakpoints = false; - - // This default debug adapter does not support hit conditional breakpoints. - response.body.supportsHitConditionalBreakpoints = false; - - // This default debug adapter does not support function breakpoints. - response.body.supportsFunctionBreakpoints = false; - - // This default debug adapter implements the 'configurationDone' request. - response.body.supportsConfigurationDoneRequest = true; - - // This default debug adapter does not support hovers based on the 'evaluate' request. - response.body.supportsEvaluateForHovers = false; - - // This default debug adapter does not support the 'stepBack' request. - response.body.supportsStepBack = false; - - // This default debug adapter does not support the 'setVariable' request. - response.body.supportsSetVariable = false; - - // This default debug adapter does not support the 'restartFrame' request. - response.body.supportsRestartFrame = false; - - // This default debug adapter does not support the 'stepInTargets' request. - response.body.supportsStepInTargetsRequest = false; - - // This default debug adapter does not support the 'gotoTargets' request. - response.body.supportsGotoTargetsRequest = false; - - // This default debug adapter does not support the 'completions' request. - response.body.supportsCompletionsRequest = false; - - // This default debug adapter does not support the 'restart' request. - response.body.supportsRestartRequest = false; - - // This default debug adapter does not support the 'exceptionOptions' attribute on the 'setExceptionBreakpoints' request. - response.body.supportsExceptionOptions = false; - - // This default debug adapter does not support the 'format' attribute on the 'variables', 'evaluate', and 'stackTrace' request. - response.body.supportsValueFormattingOptions = false; - - // This debug adapter does not support the 'exceptionInfo' request. - response.body.supportsExceptionInfoRequest = false; - - // This debug adapter does not support the 'TerminateDebuggee' attribute on the 'disconnect' request. - response.body.supportTerminateDebuggee = false; - - // This debug adapter does not support delayed loading of stack frames. - response.body.supportsDelayedStackTraceLoading = false; - - // This debug adapter does not support the 'loadedSources' request. - response.body.supportsLoadedSourcesRequest = false; - - // This debug adapter does not support the 'logMessage' attribute of the SourceBreakpoint. - response.body.supportsLogPoints = false; - - // This debug adapter does not support the 'terminateThreads' request. - response.body.supportsTerminateThreadsRequest = false; - - // This debug adapter does not support the 'setExpression' request. - response.body.supportsSetExpression = false; - - // This debug adapter does not support the 'terminate' request. - response.body.supportsTerminateRequest = false; - - // This debug adapter does not support data breakpoints. - response.body.supportsDataBreakpoints = false; - - /** This debug adapter does not support the 'readMemory' request. */ - response.body.supportsReadMemoryRequest = false; - - /** The debug adapter does not support the 'disassemble' request. */ - response.body.supportsDisassembleRequest = false; - - /** The debug adapter does not support the 'cancel' request. */ - response.body.supportsCancelRequest = false; - - /** The debug adapter does not support the 'breakpointLocations' request. */ - response.body.supportsBreakpointLocationsRequest = false; - - this.sendResponse(response); - } - - protected disconnectRequest(response: DebugProtocol.DisconnectResponse, _args: DebugProtocol.DisconnectArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - this.shutdown(); - } - - protected launchRequest(response: DebugProtocol.LaunchResponse, _args: DebugProtocol.LaunchRequestArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected attachRequest(response: DebugProtocol.AttachResponse, _args: DebugProtocol.AttachRequestArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected terminateRequest(response: DebugProtocol.TerminateResponse, _args: DebugProtocol.TerminateArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected restartRequest(response: DebugProtocol.RestartResponse, _args: DebugProtocol.RestartArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, _args: DebugProtocol.SetBreakpointsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, _args: DebugProtocol.SetFunctionBreakpointsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected setExceptionBreakPointsRequest(response: DebugProtocol.SetExceptionBreakpointsResponse, _args: DebugProtocol.SetExceptionBreakpointsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, _args: DebugProtocol.ConfigurationDoneArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected continueRequest(response: DebugProtocol.ContinueResponse, _args: DebugProtocol.ContinueArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected nextRequest(response: DebugProtocol.NextResponse, _args: DebugProtocol.NextArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected stepInRequest(response: DebugProtocol.StepInResponse, _args: DebugProtocol.StepInArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected stepOutRequest(response: DebugProtocol.StepOutResponse, _args: DebugProtocol.StepOutArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected stepBackRequest(response: DebugProtocol.StepBackResponse, _args: DebugProtocol.StepBackArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, _args: DebugProtocol.ReverseContinueArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected restartFrameRequest(response: DebugProtocol.RestartFrameResponse, _args: DebugProtocol.RestartFrameArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected gotoRequest(response: DebugProtocol.GotoResponse, _args: DebugProtocol.GotoArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected pauseRequest(response: DebugProtocol.PauseResponse, _args: DebugProtocol.PauseArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected sourceRequest(response: DebugProtocol.SourceResponse, _args: DebugProtocol.SourceArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected threadsRequest(response: DebugProtocol.ThreadsResponse, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected terminateThreadsRequest(response: DebugProtocol.TerminateThreadsResponse, _args: DebugProtocol.TerminateThreadsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, _args: DebugProtocol.StackTraceArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected scopesRequest(response: DebugProtocol.ScopesResponse, _args: DebugProtocol.ScopesArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected variablesRequest(response: DebugProtocol.VariablesResponse, _args: DebugProtocol.VariablesArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected setVariableRequest(response: DebugProtocol.SetVariableResponse, _args: DebugProtocol.SetVariableArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected setExpressionRequest(response: DebugProtocol.SetExpressionResponse, _args: DebugProtocol.SetExpressionArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected evaluateRequest(response: DebugProtocol.EvaluateResponse, _args: DebugProtocol.EvaluateArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected stepInTargetsRequest(response: DebugProtocol.StepInTargetsResponse, _args: DebugProtocol.StepInTargetsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected gotoTargetsRequest(response: DebugProtocol.GotoTargetsResponse, _args: DebugProtocol.GotoTargetsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected completionsRequest(response: DebugProtocol.CompletionsResponse, _args: DebugProtocol.CompletionsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected exceptionInfoRequest(response: DebugProtocol.ExceptionInfoResponse, _args: DebugProtocol.ExceptionInfoArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected loadedSourcesRequest(response: DebugProtocol.LoadedSourcesResponse, _args: DebugProtocol.LoadedSourcesArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected dataBreakpointInfoRequest(response: DebugProtocol.DataBreakpointInfoResponse, _args: DebugProtocol.DataBreakpointInfoArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected setDataBreakpointsRequest(response: DebugProtocol.SetDataBreakpointsResponse, _args: DebugProtocol.SetDataBreakpointsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected readMemoryRequest(response: DebugProtocol.ReadMemoryResponse, _args: DebugProtocol.ReadMemoryArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected disassembleRequest(response: DebugProtocol.DisassembleResponse, _args: DebugProtocol.DisassembleArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected cancelRequest(response: DebugProtocol.CancelResponse, _args: DebugProtocol.CancelArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - protected breakpointLocationsRequest(response: DebugProtocol.BreakpointLocationsResponse, _args: DebugProtocol.BreakpointLocationsArguments, _request?: DebugProtocol.Request): void { - this.sendResponse(response); - } - - /** - * Override this hook to implement custom requests. - */ - protected customRequest(_command: string, response: DebugProtocol.Response, _args: any, _request?: DebugProtocol.Request): void { - this.sendErrorResponse(response, 1014, 'unrecognized request', null, ErrorDestination.Telemetry); - } - - //---- protected ------------------------------------------------------------------------------------------------- - - protected convertClientLineToDebugger(line: number): number { - if (this._debuggerLinesStartAt1) { - return this._clientLinesStartAt1 ? line : line + 1; - } - return this._clientLinesStartAt1 ? line - 1 : line; - } - - protected convertDebuggerLineToClient(line: number): number { - if (this._debuggerLinesStartAt1) { - return this._clientLinesStartAt1 ? line : line - 1; - } - return this._clientLinesStartAt1 ? line + 1 : line; - } - - protected convertClientColumnToDebugger(column: number): number { - if (this._debuggerColumnsStartAt1) { - return this._clientColumnsStartAt1 ? column : column + 1; - } - return this._clientColumnsStartAt1 ? column - 1 : column; - } - - protected convertDebuggerColumnToClient(column: number): number { - if (this._debuggerColumnsStartAt1) { - return this._clientColumnsStartAt1 ? column : column - 1; - } - return this._clientColumnsStartAt1 ? column + 1 : column; - } - - protected convertClientPathToDebugger(clientPath: string): string { - if (this._clientPathsAreURIs !== this._debuggerPathsAreURIs) { - if (this._clientPathsAreURIs) { - return DebugSession.uri2path(clientPath); - } else { - return DebugSession.path2uri(clientPath); - } - } - return clientPath; - } - - protected convertDebuggerPathToClient(debuggerPath: string): string { - if (this._debuggerPathsAreURIs !== this._clientPathsAreURIs) { - if (this._debuggerPathsAreURIs) { - return DebugSession.uri2path(debuggerPath); - } else { - return DebugSession.path2uri(debuggerPath); - } - } - return debuggerPath; - } - - //---- private ------------------------------------------------------------------------------- - - private static path2uri(path: string): string { - - path = encodeURI(path); - - let uri = new URL(`file:`); // ignore 'path' for now - uri.pathname = path; // now use 'path' to get the correct percent encoding (see https://url.spec.whatwg.org) - return uri.toString(); - } - - private static uri2path(sourceUri: string): string { - - let uri = new URL(sourceUri); - let s = decodeURIComponent(uri.pathname); - return s; - } - - private static _formatPIIRegexp = /{([^}]+)}/g; - - /* - * If argument starts with '_' it is OK to send its value to telemetry. - */ - private static formatPII(format: string, excludePII: boolean, args?: { [key: string]: string }): string { - return format.replace(DebugSession._formatPIIRegexp, function (match, paramName) { - if (excludePII && paramName.length > 0 && paramName[0] !== '_') { - return match; - } - return args && args[paramName] && args.hasOwnProperty(paramName) ? - args[paramName] : - match; - }); - } -} - -//--------------------------------------------------------------------------- - -export class Handles { - - private START_HANDLE = 1000; - - private _nextHandle: number; - private _handleMap = new Map(); - - public constructor(startHandle?: number) { - this._nextHandle = typeof startHandle === 'number' ? startHandle : this.START_HANDLE; - } - - public reset(): void { - this._nextHandle = this.START_HANDLE; - this._handleMap = new Map(); - } - - public create(value: T): number { - const handle = this._nextHandle++; - this._handleMap.set(handle, value); - return handle; - } - - public get(handle: number, dflt?: T): T | undefined { - return this._handleMap.get(handle) || dflt; - } -} - -//--------------------------------------------------------------------------- - -class MockConfigurationProvider implements vscode.DebugConfigurationProvider { - - /** - * Massage a debug configuration just before a debug session is being launched, - * e.g. add all missing attributes to the debug configuration. - */ - resolveDebugConfiguration(_folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, _token?: vscode.CancellationToken): vscode.ProviderResult { - - // if launch.json is missing or empty - if (!config.type && !config.request && !config.name) { - const editor = vscode.window.activeTextEditor; - if (editor && editor.document.languageId === 'markdown') { - config.type = 'mock'; - config.name = 'Launch'; - config.request = 'launch'; - config.program = '${file}'; - config.stopOnEntry = true; - } - } - - if (!config.program) { - return vscode.window.showInformationMessage('Cannot find a program to debug').then(_ => { - return undefined; // abort launch - }); - } - - return config; - } -} - -export class MockDebugAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory { - - constructor(private memfs: MemFS) { - } - - createDebugAdapterDescriptor(_session: vscode.DebugSession, _executable: vscode.DebugAdapterExecutable | undefined): vscode.ProviderResult { - return new vscode.DebugAdapterInlineImplementation(new MockDebugSession(this.memfs)); - } -} - -function basename(path: string): string { - const pos = path.lastIndexOf('/'); - if (pos >= 0) { - return path.substring(pos + 1); - } - return path; -} - -function timeout(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -/** - * This interface describes the mock-debug specific launch attributes - * (which are not part of the Debug Adapter Protocol). - * The schema for these attributes lives in the package.json of the mock-debug extension. - * The interface should always match this schema. - */ -interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { - /** An absolute path to the "program" to debug. */ - program: string; - /** Automatically stop target after launch. If not specified, target does not stop. */ - stopOnEntry?: boolean; - /** enable logging the Debug Adapter Protocol */ - trace?: boolean; -} - -export class MockDebugSession extends DebugSession { - - // we don't support multiple threads, so we can use a hardcoded ID for the default thread - private static THREAD_ID = 1; - - // a Mock runtime (or debugger) - private _runtime: MockRuntime; - - private _variableHandles = new Handles(); - - //private _configurationDone = new Subject(); - - private promiseResolve?: () => void; - private _configurationDone = new Promise((r, _e) => { - this.promiseResolve = r; - setTimeout(r, 1000); - }); - - private _cancelationTokens = new Map(); - private _isLongrunning = new Map(); - - /** - * Creates a new debug adapter that is used for one debug session. - * We configure the default implementation of a debug adapter here. - */ - public constructor(memfs: MemFS) { - - super(); - - // this debugger uses zero-based lines and columns - this.setDebuggerLinesStartAt1(false); - this.setDebuggerColumnsStartAt1(false); - - this._runtime = new MockRuntime(memfs); - - // setup event handlers - this._runtime.onStopOnEntry(() => { - this.sendEvent(new StoppedEvent('entry', MockDebugSession.THREAD_ID)); - }); - this._runtime.onStopOnStep(() => { - this.sendEvent(new StoppedEvent('step', MockDebugSession.THREAD_ID)); - }); - this._runtime.onStopOnBreakpoint(() => { - this.sendEvent(new StoppedEvent('breakpoint', MockDebugSession.THREAD_ID)); - }); - this._runtime.onStopOnDataBreakpoint(() => { - this.sendEvent(new StoppedEvent('data breakpoint', MockDebugSession.THREAD_ID)); - }); - this._runtime.onStopOnException(() => { - this.sendEvent(new StoppedEvent('exception', MockDebugSession.THREAD_ID)); - }); - this._runtime.onBreakpointValidated((bp: MockBreakpoint) => { - this.sendEvent(new BreakpointEvent('changed', { verified: bp.verified, id: bp.id })); - }); - this._runtime.onOutput(oe => { - const e: DebugProtocol.OutputEvent = new OutputEvent(`${oe.text}\n`); - e.body.source = this.createSource(oe.filePath); - e.body.line = this.convertDebuggerLineToClient(oe.line); - e.body.column = this.convertDebuggerColumnToClient(oe.column); - this.sendEvent(e); - }); - this._runtime.onEnd(() => { - this.sendEvent(new TerminatedEvent()); - }); - } - - /** - * The 'initialize' request is the first request called by the frontend - * to interrogate the features the debug adapter provides. - */ - protected initializeRequest(response: DebugProtocol.InitializeResponse, _args: DebugProtocol.InitializeRequestArguments): void { - - // build and return the capabilities of this debug adapter: - response.body = response.body || {}; - - // the adapter implements the configurationDoneRequest. - response.body.supportsConfigurationDoneRequest = true; - - // make VS Code to use 'evaluate' when hovering over source - response.body.supportsEvaluateForHovers = true; - - // make VS Code to show a 'step back' button - response.body.supportsStepBack = true; - - // make VS Code to support data breakpoints - response.body.supportsDataBreakpoints = true; - - // make VS Code to support completion in REPL - response.body.supportsCompletionsRequest = true; - response.body.completionTriggerCharacters = ['.', '[']; - - // make VS Code to send cancelRequests - response.body.supportsCancelRequest = true; - - // make VS Code send the breakpointLocations request - response.body.supportsBreakpointLocationsRequest = true; - - this.sendResponse(response); - - // since this debug adapter can accept configuration requests like 'setBreakpoint' at any time, - // we request them early by sending an 'initializeRequest' to the frontend. - // The frontend will end the configuration sequence by calling 'configurationDone' request. - this.sendEvent(new InitializedEvent()); - } - - /** - * Called at the end of the configuration sequence. - * Indicates that all breakpoints etc. have been sent to the DA and that the 'launch' can start. - */ - protected configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.ConfigurationDoneArguments): void { - super.configurationDoneRequest(response, args); - - // notify the launchRequest that configuration has finished - //this._configurationDone.notify(); - if (this.promiseResolve) { - this.promiseResolve(); - } - } - - protected async launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments) { - - // make sure to 'Stop' the buffered logging if 'trace' is not set - //logger.setup(args.trace ? Logger.LogLevel.Verbose : Logger.LogLevel.Stop, false); - - // wait until configuration has finished (and configurationDoneRequest has been called) - await this._configurationDone; - - // start the program in the runtime - this._runtime.start(`memfs:${args.program}`, !!args.stopOnEntry); - - this.sendResponse(response); - } - - protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void { - - const path = args.source.path; - const clientLines = args.lines || []; - - // clear all breakpoints for this file - this._runtime.clearBreakpoints(path); - - // set and verify breakpoint locations - const actualBreakpoints = clientLines.map(l => { - let { verified, line, id } = this._runtime.setBreakPoint(path, this.convertClientLineToDebugger(l)); - const bp = new Breakpoint(verified, this.convertDebuggerLineToClient(line)); - bp.id = id; - return bp; - }); - - // send back the actual breakpoint positions - response.body = { - breakpoints: actualBreakpoints - }; - this.sendResponse(response); - } - - protected breakpointLocationsRequest(response: DebugProtocol.BreakpointLocationsResponse, args: DebugProtocol.BreakpointLocationsArguments, _request?: DebugProtocol.Request): void { - - if (args.source.path) { - const bps = this._runtime.getBreakpoints(args.source.path, this.convertClientLineToDebugger(args.line)); - response.body = { - breakpoints: bps.map(col => { - return { - line: args.line, - column: this.convertDebuggerColumnToClient(col) - }; - }) - }; - } else { - response.body = { - breakpoints: [] - }; - } - this.sendResponse(response); - } - - protected threadsRequest(response: DebugProtocol.ThreadsResponse): void { - - // runtime supports no threads so just return a default thread. - response.body = { - threads: [ - new Thread(MockDebugSession.THREAD_ID, 'thread 1') - ] - }; - this.sendResponse(response); - } - - protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void { - - const startFrame = typeof args.startFrame === 'number' ? args.startFrame : 0; - const maxLevels = typeof args.levels === 'number' ? args.levels : 1000; - const endFrame = startFrame + maxLevels; - - const stk = this._runtime.stack(startFrame, endFrame); - - response.body = { - stackFrames: stk.frames.map(f => new StackFrame(f.index, f.name, this.createSource(f.file), this.convertDebuggerLineToClient(f.line))), - totalFrames: stk.count - }; - this.sendResponse(response); - } - - protected scopesRequest(response: DebugProtocol.ScopesResponse, _args: DebugProtocol.ScopesArguments): void { - - response.body = { - scopes: [ - new Scope('Local', this._variableHandles.create('local'), false), - new Scope('Global', this._variableHandles.create('global'), true) - ] - }; - this.sendResponse(response); - } - - protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments, request?: DebugProtocol.Request) { - - const variables: DebugProtocol.Variable[] = []; - - if (this._isLongrunning.get(args.variablesReference)) { - // long running - - if (request) { - this._cancelationTokens.set(request.seq, false); - } - - for (let i = 0; i < 100; i++) { - await timeout(1000); - variables.push({ - name: `i_${i}`, - type: 'integer', - value: `${i}`, - variablesReference: 0 - }); - if (request && this._cancelationTokens.get(request.seq)) { - break; - } - } - - if (request) { - this._cancelationTokens.delete(request.seq); - } - - } else { - - const id = this._variableHandles.get(args.variablesReference); - - if (id) { - variables.push({ - name: id + '_i', - type: 'integer', - value: '123', - variablesReference: 0 - }); - variables.push({ - name: id + '_f', - type: 'float', - value: '3.14', - variablesReference: 0 - }); - variables.push({ - name: id + '_s', - type: 'string', - value: 'hello world', - variablesReference: 0 - }); - variables.push({ - name: id + '_o', - type: 'object', - value: 'Object', - variablesReference: this._variableHandles.create(id + '_o') - }); - - // cancelation support for long running requests - const nm = id + '_long_running'; - const ref = this._variableHandles.create(id + '_lr'); - variables.push({ - name: nm, - type: 'object', - value: 'Object', - variablesReference: ref - }); - this._isLongrunning.set(ref, true); - } - } - - response.body = { - variables: variables - }; - this.sendResponse(response); - } - - protected continueRequest(response: DebugProtocol.ContinueResponse, _args: DebugProtocol.ContinueArguments): void { - this._runtime.continue(); - this.sendResponse(response); - } - - protected reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, _args: DebugProtocol.ReverseContinueArguments): void { - this._runtime.continue(true); - this.sendResponse(response); - } - - protected nextRequest(response: DebugProtocol.NextResponse, _args: DebugProtocol.NextArguments): void { - this._runtime.step(); - this.sendResponse(response); - } - - protected stepBackRequest(response: DebugProtocol.StepBackResponse, _args: DebugProtocol.StepBackArguments): void { - this._runtime.step(true); - this.sendResponse(response); - } - - protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void { - - let reply: string | undefined = undefined; - - if (args.context === 'repl') { - // 'evaluate' supports to create and delete breakpoints from the 'repl': - const matches = /new +([0-9]+)/.exec(args.expression); - if (matches && matches.length === 2) { - if (this._runtime.sourceFile) { - const mbp = this._runtime.setBreakPoint(this._runtime.sourceFile, this.convertClientLineToDebugger(parseInt(matches[1]))); - const bp = new Breakpoint(mbp.verified, this.convertDebuggerLineToClient(mbp.line), undefined, this.createSource(this._runtime.sourceFile)); - bp.id = mbp.id; - this.sendEvent(new BreakpointEvent('new', bp)); - reply = `breakpoint created`; - } - } else { - const matches = /del +([0-9]+)/.exec(args.expression); - if (matches && matches.length === 2) { - const mbp = this._runtime.sourceFile ? this._runtime.clearBreakPoint(this._runtime.sourceFile, this.convertClientLineToDebugger(parseInt(matches[1]))) : undefined; - if (mbp) { - const bp = new Breakpoint(false); - bp.id = mbp.id; - this.sendEvent(new BreakpointEvent('removed', bp)); - reply = `breakpoint deleted`; - } - } - } - } - - response.body = { - result: reply ? reply : `evaluate(context: '${args.context}', '${args.expression}')`, - variablesReference: 0 - }; - this.sendResponse(response); - } - - protected dataBreakpointInfoRequest(response: DebugProtocol.DataBreakpointInfoResponse, args: DebugProtocol.DataBreakpointInfoArguments): void { - - response.body = { - dataId: null, - description: 'cannot break on data access', - accessTypes: undefined, - canPersist: false - }; - - if (args.variablesReference && args.name) { - const id = this._variableHandles.get(args.variablesReference); - if (id && id.startsWith('global_')) { - response.body.dataId = args.name; - response.body.description = args.name; - response.body.accessTypes = ['read']; - response.body.canPersist = false; - } - } - - this.sendResponse(response); - } - - protected setDataBreakpointsRequest(response: DebugProtocol.SetDataBreakpointsResponse, args: DebugProtocol.SetDataBreakpointsArguments): void { - - // clear all data breakpoints - this._runtime.clearAllDataBreakpoints(); - - response.body = { - breakpoints: [] - }; - - for (let dbp of args.breakpoints) { - // assume that id is the "address" to break on - const ok = this._runtime.setDataBreakpoint(dbp.dataId); - response.body.breakpoints.push({ - verified: ok - }); - } - - this.sendResponse(response); - } - - protected completionsRequest(response: DebugProtocol.CompletionsResponse, _args: DebugProtocol.CompletionsArguments): void { - - response.body = { - targets: [ - { - label: 'item 10', - sortText: '10' - }, - { - label: 'item 1', - sortText: '01' - }, - { - label: 'item 2', - sortText: '02' - } - ] - }; - this.sendResponse(response); - } - - protected cancelRequest(_response: DebugProtocol.CancelResponse, args: DebugProtocol.CancelArguments) { - if (args.requestId) { - this._cancelationTokens.set(args.requestId, true); - } - } - - //---- helpers - - private createSource(filePath: string): Source { - return new Source(basename(filePath), this.convertDebuggerPathToClient(filePath), undefined, undefined, 'mock-adapter-data'); - } -} - -//------------------------------------------------------------------------------------------------------------------------------------------ - - -/*--------------------------------------------------------- - * Copyright (C) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------*/ - -export interface MockBreakpoint { - id: number; - line: number; - verified: boolean; -} - -export interface MockOutputEvent { - text: string; - filePath: string; - line: number; - column: number; -} - -/** - * A Mock runtime with minimal debugger functionality. - */ -export class MockRuntime { - - private stopOnEntry = new vscode.EventEmitter(); - onStopOnEntry: vscode.Event = this.stopOnEntry.event; - - private stopOnStep = new vscode.EventEmitter(); - onStopOnStep: vscode.Event = this.stopOnStep.event; - - private stopOnBreakpoint = new vscode.EventEmitter(); - onStopOnBreakpoint: vscode.Event = this.stopOnBreakpoint.event; - - private stopOnDataBreakpoint = new vscode.EventEmitter(); - onStopOnDataBreakpoint: vscode.Event = this.stopOnDataBreakpoint.event; - - private stopOnException = new vscode.EventEmitter(); - onStopOnException: vscode.Event = this.stopOnException.event; - - private breakpointValidated = new vscode.EventEmitter(); - onBreakpointValidated: vscode.Event = this.breakpointValidated.event; - - private output = new vscode.EventEmitter(); - onOutput: vscode.Event = this.output.event; - - private end = new vscode.EventEmitter(); - onEnd: vscode.Event = this.end.event; - - - // the initial (and one and only) file we are 'debugging' - private _sourceFile?: string; - public get sourceFile() { - return this._sourceFile; - } - - // the contents (= lines) of the one and only file - private _sourceLines: string[] = []; - - // This is the next line that will be 'executed' - private _currentLine = 0; - - // maps from sourceFile to array of Mock breakpoints - private _breakPoints = new Map(); - - // since we want to send breakpoint events, we will assign an id to every event - // so that the frontend can match events with breakpoints. - private _breakpointId = 1; - - private _breakAddresses = new Set(); - - constructor(private memfs: MemFS) { - } - - /** - * Start executing the given program. - */ - public start(program: string, stopOnEntry: boolean) { - - this.loadSource(program); - this._currentLine = -1; - - if (this._sourceFile) { - this.verifyBreakpoints(this._sourceFile); - } - - if (stopOnEntry) { - // we step once - this.step(false, this.stopOnEntry); - } else { - // we just start to run until we hit a breakpoint or an exception - this.continue(); - } - } - - /** - * Continue execution to the end/beginning. - */ - public continue(reverse = false) { - this.run(reverse, undefined); - } - - /** - * Step to the next/previous non empty line. - */ - public step(reverse = false, event = this.stopOnStep) { - this.run(reverse, event); - } - - /** - * Returns a fake 'stacktrace' where every 'stackframe' is a word from the current line. - */ - public stack(startFrame: number, endFrame: number): { frames: any[], count: number } { - - const words = this._sourceLines[this._currentLine].trim().split(/\s+/); - - const frames = new Array(); - // every word of the current line becomes a stack frame. - for (let i = startFrame; i < Math.min(endFrame, words.length); i++) { - const name = words[i]; // use a word of the line as the stackframe name - frames.push({ - index: i, - name: `${name}(${i})`, - file: this._sourceFile, - line: this._currentLine - }); - } - return { - frames: frames, - count: words.length - }; - } - - public getBreakpoints(_path: string, line: number): number[] { - - const l = this._sourceLines[line]; - - let sawSpace = true; - const bps: number[] = []; - for (let i = 0; i < l.length; i++) { - if (l[i] !== ' ') { - if (sawSpace) { - bps.push(i); - sawSpace = false; - } - } else { - sawSpace = true; - } - } - - return bps; - } - - /* - * Set breakpoint in file with given line. - */ - public setBreakPoint(path: string, line: number): MockBreakpoint { - - const bp = { verified: false, line, id: this._breakpointId++ }; - let bps = this._breakPoints.get(path); - if (!bps) { - bps = new Array(); - this._breakPoints.set(path, bps); - } - bps.push(bp); - - this.verifyBreakpoints(path); - - return bp; - } - - /* - * Clear breakpoint in file with given line. - */ - public clearBreakPoint(path: string, line: number): MockBreakpoint | undefined { - let bps = this._breakPoints.get(path); - if (bps) { - const index = bps.findIndex(bp => bp.line === line); - if (index >= 0) { - const bp = bps[index]; - bps.splice(index, 1); - return bp; - } - } - return undefined; - } - - /* - * Clear all breakpoints for file. - */ - public clearBreakpoints(path: string): void { - this._breakPoints.delete(path); - } - - /* - * Set data breakpoint. - */ - public setDataBreakpoint(address: string): boolean { - if (address) { - this._breakAddresses.add(address); - return true; - } - return false; - } - - /* - * Clear all data breakpoints. - */ - public clearAllDataBreakpoints(): void { - this._breakAddresses.clear(); - } - - // private methods - - private loadSource(file: string) { - if (this._sourceFile !== file) { - this._sourceFile = file; - - const _textDecoder = new TextDecoder(); - - const uri = vscode.Uri.parse(file); - const content = _textDecoder.decode(this.memfs.readFile(uri)); - this._sourceLines = content.split('\n'); - - //this._sourceLines = readFileSync(this._sourceFile).toString().split('\n'); - } - } - - /** - * Run through the file. - * If stepEvent is specified only run a single step and emit the stepEvent. - */ - private run(reverse = false, stepEvent?: vscode.EventEmitter): void { - if (reverse) { - for (let ln = this._currentLine - 1; ln >= 0; ln--) { - if (this.fireEventsForLine(ln, stepEvent)) { - this._currentLine = ln; - return; - } - } - // no more lines: stop at first line - this._currentLine = 0; - this.stopOnEntry.fire(); - } else { - for (let ln = this._currentLine + 1; ln < this._sourceLines.length; ln++) { - if (this.fireEventsForLine(ln, stepEvent)) { - this._currentLine = ln; - return; - } - } - // no more lines: run to end - this.end.fire(); - } - } - - private verifyBreakpoints(path: string): void { - let bps = this._breakPoints.get(path); - if (bps) { - this.loadSource(path); - bps.forEach(bp => { - if (!bp.verified && bp.line < this._sourceLines.length) { - const srcLine = this._sourceLines[bp.line].trim(); - - // if a line is empty or starts with '+' we don't allow to set a breakpoint but move the breakpoint down - if (srcLine.length === 0 || srcLine.indexOf('+') === 0) { - bp.line++; - } - // if a line starts with '-' we don't allow to set a breakpoint but move the breakpoint up - if (srcLine.indexOf('-') === 0) { - bp.line--; - } - // don't set 'verified' to true if the line contains the word 'lazy' - // in this case the breakpoint will be verified 'lazy' after hitting it once. - if (srcLine.indexOf('lazy') < 0) { - bp.verified = true; - this.breakpointValidated.fire(bp); - } - } - }); - } - } - - /** - * Fire events if line has a breakpoint or the word 'exception' is found. - * Returns true is execution needs to stop. - */ - private fireEventsForLine(ln: number, stepEvent?: vscode.EventEmitter): boolean { - - const line = this._sourceLines[ln].trim(); - - // if 'log(...)' found in source -> send argument to debug console - const matches = /log\((.*)\)/.exec(line); - if (matches && matches.length === 2) { - if (this._sourceFile) { - this.output.fire({ text: matches[1], filePath: this._sourceFile, line: ln, column: matches.index }); - } - } - - // if a word in a line matches a data breakpoint, fire a 'dataBreakpoint' event - const words = line.split(' '); - for (let word of words) { - if (this._breakAddresses.has(word)) { - this.stopOnDataBreakpoint.fire(); - return true; - } - } - - // if word 'exception' found in source -> throw exception - if (line.indexOf('exception') >= 0) { - this.stopOnException.fire(); - return true; - } - - // is there a breakpoint? - const breakpoints = this._sourceFile ? this._breakPoints.get(this._sourceFile) : undefined; - if (breakpoints) { - const bps = breakpoints.filter(bp => bp.line === ln); - if (bps.length > 0) { - - // send 'stopped' event - this.stopOnBreakpoint.fire(); - - // the following shows the use of 'breakpoint' events to update properties of a breakpoint in the UI - // if breakpoint is not yet verified, verify it now and send a 'breakpoint' update event - if (!bps[0].verified) { - bps[0].verified = true; - this.breakpointValidated.fire(bps[0]); - } - return true; - } - } - - // non-empty line - if (stepEvent && line.length > 0) { - stepEvent.fire(); - return true; - } - - // nothing interesting found -> continue - return false; - } -} diff --git a/extensions/vscode-web-playground/src/memfs.ts b/extensions/vscode-web-playground/src/memfs.ts deleted file mode 100644 index 9a135109fb4..00000000000 --- a/extensions/vscode-web-playground/src/memfs.ts +++ /dev/null @@ -1,449 +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 { - CancellationToken, - Disposable, - Event, - EventEmitter, - FileChangeEvent, - FileChangeType, - FileSearchOptions, - FileSearchProvider, - FileSearchQuery, - FileStat, - FileSystemError, - FileSystemProvider, - FileType, - Position, - Progress, - ProviderResult, - Range, - TextSearchComplete, - TextSearchOptions, - TextSearchQuery, - TextSearchProvider, - TextSearchResult, - Uri, - workspace, -} from 'vscode'; -import { largeTSFile, getImageFile, debuggableFile, windows1251File, gbkFile } from './exampleFiles'; - -export class File implements FileStat { - - type: FileType; - ctime: number; - mtime: number; - size: number; - - name: string; - data?: Uint8Array; - - constructor(public uri: Uri, name: string) { - this.type = FileType.File; - this.ctime = Date.now(); - this.mtime = Date.now(); - this.size = 0; - this.name = name; - } -} - -export class Directory implements FileStat { - - type: FileType; - ctime: number; - mtime: number; - size: number; - - name: string; - entries: Map; - - constructor(public uri: Uri, name: string) { - this.type = FileType.Directory; - this.ctime = Date.now(); - this.mtime = Date.now(); - this.size = 0; - this.name = name; - this.entries = new Map(); - } -} - -export type Entry = File | Directory; - -const textEncoder = new TextEncoder(); - -export class MemFS implements FileSystemProvider, FileSearchProvider, TextSearchProvider, Disposable { - static scheme = 'memfs'; - - private readonly disposable: Disposable; - - constructor() { - this.disposable = Disposable.from( - workspace.registerFileSystemProvider(MemFS.scheme, this, { isCaseSensitive: true }), - workspace.registerFileSearchProvider(MemFS.scheme, this), - workspace.registerTextSearchProvider(MemFS.scheme, this) - ); - } - - dispose() { - this.disposable?.dispose(); - } - - seed() { - this.createDirectory(Uri.parse(`memfs:/sample-folder/`)); - - // most common files types - this.writeFile(Uri.parse(`memfs:/sample-folder/large.ts`), textEncoder.encode(largeTSFile), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.txt`), textEncoder.encode('foo'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.html`), textEncoder.encode('

Hello

'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.js`), textEncoder.encode('console.log("JavaScript")'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.json`), textEncoder.encode('{ "json": true }'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.ts`), textEncoder.encode('console.log("TypeScript")'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.css`), textEncoder.encode('* { color: green; }'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.md`), textEncoder.encode(debuggableFile), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.xml`), textEncoder.encode(''), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.py`), textEncoder.encode('import base64, sys; base64.decode(open(sys.argv[1], "rb"), open(sys.argv[2], "wb"))'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.php`), textEncoder.encode('&1\'); ?>'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.yaml`), textEncoder.encode('- just: write something'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/file.jpg`), getImageFile(), { create: true, overwrite: true }); - - // some more files & folders - this.createDirectory(Uri.parse(`memfs:/sample-folder/folder/`)); - this.createDirectory(Uri.parse(`memfs:/sample-folder/large/`)); - this.createDirectory(Uri.parse(`memfs:/sample-folder/xyz/`)); - this.createDirectory(Uri.parse(`memfs:/sample-folder/xyz/abc`)); - this.createDirectory(Uri.parse(`memfs:/sample-folder/xyz/def`)); - - this.writeFile(Uri.parse(`memfs:/sample-folder/folder/empty.txt`), new Uint8Array(0), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/folder/empty.foo`), new Uint8Array(0), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/folder/file.ts`), textEncoder.encode('let a:number = true; console.log(a);'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/large/rnd.foo`), randomData(50000), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/xyz/UPPER.txt`), textEncoder.encode('UPPER'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/xyz/upper.txt`), textEncoder.encode('upper'), { create: true, overwrite: true }); - this.writeFile(Uri.parse(`memfs:/sample-folder/xyz/def/foo.md`), textEncoder.encode('*MemFS*'), { create: true, overwrite: true }); - - // some files in different encodings - this.createDirectory(Uri.parse(`memfs:/sample-folder/encodings/`)); - this.writeFile( - Uri.parse(`memfs:/sample-folder/encodings/windows1251.txt`), - windows1251File, - { create: true, overwrite: true } - ); - this.writeFile( - Uri.parse(`memfs:/sample-folder/encodings/gbk.txt`), - gbkFile, - { create: true, overwrite: true } - ); - } - - root = new Directory(Uri.parse('memfs:/'), ''); - - // --- manage file metadata - - stat(uri: Uri): FileStat { - return this._lookup(uri, false); - } - - readDirectory(uri: Uri): [string, FileType][] { - const entry = this._lookupAsDirectory(uri, false); - let result: [string, FileType][] = []; - for (const [name, child] of entry.entries) { - result.push([name, child.type]); - } - return result; - } - - // --- manage file contents - - readFile(uri: Uri): Uint8Array { - const data = this._lookupAsFile(uri, false).data; - if (data) { - return data; - } - throw FileSystemError.FileNotFound(); - } - - writeFile(uri: Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void { - let basename = this._basename(uri.path); - let parent = this._lookupParentDirectory(uri); - let entry = parent.entries.get(basename); - if (entry instanceof Directory) { - throw FileSystemError.FileIsADirectory(uri); - } - if (!entry && !options.create) { - throw FileSystemError.FileNotFound(uri); - } - if (entry && options.create && !options.overwrite) { - throw FileSystemError.FileExists(uri); - } - if (!entry) { - entry = new File(uri, basename); - parent.entries.set(basename, entry); - this._fireSoon({ type: FileChangeType.Created, uri }); - } - entry.mtime = Date.now(); - entry.size = content.byteLength; - entry.data = content; - - this._fireSoon({ type: FileChangeType.Changed, uri }); - } - - // --- manage files/folders - - rename(oldUri: Uri, newUri: Uri, options: { overwrite: boolean }): void { - if (!options.overwrite && this._lookup(newUri, true)) { - throw FileSystemError.FileExists(newUri); - } - - let entry = this._lookup(oldUri, false); - let oldParent = this._lookupParentDirectory(oldUri); - - let newParent = this._lookupParentDirectory(newUri); - let newName = this._basename(newUri.path); - - oldParent.entries.delete(entry.name); - entry.name = newName; - newParent.entries.set(newName, entry); - - this._fireSoon( - { type: FileChangeType.Deleted, uri: oldUri }, - { type: FileChangeType.Created, uri: newUri } - ); - } - - delete(uri: Uri): void { - let dirname = uri.with({ path: this._dirname(uri.path) }); - let basename = this._basename(uri.path); - let parent = this._lookupAsDirectory(dirname, false); - if (!parent.entries.has(basename)) { - throw FileSystemError.FileNotFound(uri); - } - parent.entries.delete(basename); - parent.mtime = Date.now(); - parent.size -= 1; - this._fireSoon({ type: FileChangeType.Changed, uri: dirname }, { uri, type: FileChangeType.Deleted }); - } - - createDirectory(uri: Uri): void { - let basename = this._basename(uri.path); - let dirname = uri.with({ path: this._dirname(uri.path) }); - let parent = this._lookupAsDirectory(dirname, false); - - let entry = new Directory(uri, basename); - parent.entries.set(entry.name, entry); - parent.mtime = Date.now(); - parent.size += 1; - this._fireSoon({ type: FileChangeType.Changed, uri: dirname }, { type: FileChangeType.Created, uri }); - } - - // --- lookup - - private _lookup(uri: Uri, silent: false): Entry; - private _lookup(uri: Uri, silent: boolean): Entry | undefined; - private _lookup(uri: Uri, silent: boolean): Entry | undefined { - let parts = uri.path.split('/'); - let entry: Entry = this.root; - for (const part of parts) { - if (!part) { - continue; - } - let child: Entry | undefined; - if (entry instanceof Directory) { - child = entry.entries.get(part); - } - if (!child) { - if (!silent) { - throw FileSystemError.FileNotFound(uri); - } else { - return undefined; - } - } - entry = child; - } - return entry; - } - - private _lookupAsDirectory(uri: Uri, silent: boolean): Directory { - let entry = this._lookup(uri, silent); - if (entry instanceof Directory) { - return entry; - } - throw FileSystemError.FileNotADirectory(uri); - } - - private _lookupAsFile(uri: Uri, silent: boolean): File { - let entry = this._lookup(uri, silent); - if (entry instanceof File) { - return entry; - } - throw FileSystemError.FileIsADirectory(uri); - } - - private _lookupParentDirectory(uri: Uri): Directory { - const dirname = uri.with({ path: this._dirname(uri.path) }); - return this._lookupAsDirectory(dirname, false); - } - - // --- manage file events - - private _emitter = new EventEmitter(); - private _bufferedEvents: FileChangeEvent[] = []; - private _fireSoonHandle?: any; - - readonly onDidChangeFile: Event = this._emitter.event; - - watch(_resource: Uri): Disposable { - // ignore, fires for all changes... - return new Disposable(() => { }); - } - - private _fireSoon(...events: FileChangeEvent[]): void { - this._bufferedEvents.push(...events); - - if (this._fireSoonHandle) { - clearTimeout(this._fireSoonHandle); - } - - this._fireSoonHandle = setTimeout(() => { - this._emitter.fire(this._bufferedEvents); - this._bufferedEvents.length = 0; - }, 5); - } - - // --- path utils - - private _basename(path: string): string { - path = this._rtrim(path, '/'); - if (!path) { - return ''; - } - - return path.substr(path.lastIndexOf('/') + 1); - } - - private _dirname(path: string): string { - path = this._rtrim(path, '/'); - if (!path) { - return '/'; - } - - return path.substr(0, path.lastIndexOf('/')); - } - - private _rtrim(haystack: string, needle: string): string { - if (!haystack || !needle) { - return haystack; - } - - const needleLen = needle.length, - haystackLen = haystack.length; - - if (needleLen === 0 || haystackLen === 0) { - return haystack; - } - - let offset = haystackLen, - idx = -1; - - while (true) { - idx = haystack.lastIndexOf(needle, offset - 1); - if (idx === -1 || idx + needleLen !== offset) { - break; - } - if (idx === 0) { - return ''; - } - offset = idx; - } - - return haystack.substring(0, offset); - } - - private _getFiles(): Set { - const files = new Set(); - - this._doGetFiles(this.root, files); - - return files; - } - - private _doGetFiles(dir: Directory, files: Set): void { - dir.entries.forEach(entry => { - if (entry instanceof File) { - files.add(entry); - } else { - this._doGetFiles(entry, files); - } - }); - } - - private _convertSimple2RegExpPattern(pattern: string): string { - return pattern.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&').replace(/[\*]/g, '.*'); - } - - // --- search provider - - provideFileSearchResults(query: FileSearchQuery, _options: FileSearchOptions, _token: CancellationToken): ProviderResult { - return this._findFiles(query.pattern); - } - - private _findFiles(query: string | undefined): Uri[] { - const files = this._getFiles(); - const result: Uri[] = []; - - const pattern = query ? new RegExp(this._convertSimple2RegExpPattern(query)) : null; - - for (const file of files) { - if (!pattern || pattern.exec(file.name)) { - result.push(file.uri); - } - } - - return result; - } - - private _textDecoder = new TextDecoder(); - - provideTextSearchResults(query: TextSearchQuery, options: TextSearchOptions, progress: Progress, _token: CancellationToken) { - const result: TextSearchComplete = { limitHit: false }; - - const files = this._findFiles(options.includes[0]); - if (files) { - for (const file of files) { - const content = this._textDecoder.decode(this.readFile(file)); - - const lines = content.split('\n'); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - const index = line.indexOf(query.pattern); - if (index !== -1) { - progress.report({ - uri: file, - ranges: new Range(new Position(i, index), new Position(i, index + query.pattern.length)), - preview: { - text: line, - matches: new Range(new Position(0, index), new Position(0, index + query.pattern.length)) - } - }); - } - } - } - } - - return result; - } -} - -function randomData(lineCnt: number, lineLen = 155): Uint8Array { - let lines: string[] = []; - for (let i = 0; i < lineCnt; i++) { - let line = ''; - while (line.length < lineLen) { - line += Math.random().toString(2 + (i % 34)).substr(2); - } - lines.push(line.substr(0, lineLen)); - } - return textEncoder.encode(lines.join('\n')); -} diff --git a/extensions/vscode-web-playground/tsconfig.json b/extensions/vscode-web-playground/tsconfig.json deleted file mode 100644 index 633da7fad77..00000000000 --- a/extensions/vscode-web-playground/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../shared.tsconfig.json", - "compilerOptions": { - "outDir": "./out", - "lib": [ - "dom", - "dom.iterable", - "es2018" - ] - }, - "include": [ - "src/**/*" - ] -} diff --git a/extensions/vscode-web-playground/yarn.lock b/extensions/vscode-web-playground/yarn.lock deleted file mode 100644 index b29fc8fc61d..00000000000 --- a/extensions/vscode-web-playground/yarn.lock +++ /dev/null @@ -1,109 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/mocha@2.2.43": - version "2.2.43" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.43.tgz#03c54589c43ad048cbcbfd63999b55d0424eec27" - integrity sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw== - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -charenc@~0.0.1: - version "0.0.2" - resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" - integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= - -crypt@~0.0.1: - version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= - -debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -is-buffer@~1.1.1: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -lodash@^4.16.4: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -md5@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" - integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= - dependencies: - charenc "~0.0.1" - crypt "~0.0.1" - is-buffer "~1.1.1" - -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mkdirp@~0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mocha-junit-reporter@^1.17.0: - version "1.23.3" - resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.3.tgz#941e219dd759ed732f8641e165918aa8b167c981" - integrity sha512-ed8LqbRj1RxZfjt/oC9t12sfrWsjZ3gNnbhV1nuj9R/Jb5/P3Xb4duv2eCfCDMYH+fEu0mqca7m4wsiVjsxsvA== - dependencies: - debug "^2.2.0" - md5 "^2.1.0" - mkdirp "~0.5.1" - strip-ansi "^4.0.0" - xml "^1.0.0" - -mocha-multi-reporters@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz#cc7f3f4d32f478520941d852abb64d9988587d82" - integrity sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI= - dependencies: - debug "^3.1.0" - lodash "^4.16.4" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -xml@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" - integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 86223e77212..24b3bceafc9 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,86 +2,7 @@ # yarn lockfile v1 -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -glob@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -typescript@3.9.7: - version "3.9.7" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" - integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +typescript@^4.0.2-insiders.20200818: + version "4.0.2-insiders.20200818" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2-insiders.20200818.tgz#50d949f8d7ae460ce2f2f5a4121ff020a54711e8" + integrity sha512-5/y/W/EFwly+UAm8X77bPjh8FG1GsLRRtrWApIIAsT6kcN9auKhHyrEIUYSahm/WX9F3f7svRxKm6eddvEzyAw== diff --git a/package.json b/package.json index 63036471803..a50ce5cc307 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", - "version": "1.48.0", - "distro": "a4dd690fc5b9555a6707734135e5e8ce0c35e5a5", + "version": "1.49.0", + "distro": "30ea358b7ad9b2e701d90077c2ff970e87a7a06b", "author": { "name": "Microsoft Corporation" }, @@ -40,7 +40,7 @@ "valid-layers-check": "node build/lib/layersChecker.js", "strict-function-types-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictFunctionTypes", "update-distro": "node build/npm/update-distro.js", - "web": "node resources/serverless/code-web.js", + "web": "node resources/web/code-web.js", "compile-web": "gulp compile-web --max_old_space_size=4095", "watch-web": "gulp watch-web --max_old_space_size=4095", "eslint": "eslint -c .eslintrc.json --rulesdir ./build/lib/eslint --ext .ts --ext .js ./src/vs ./extensions" @@ -62,6 +62,7 @@ "semver-umd": "^5.5.7", "spdlog": "^0.11.1", "sudo-prompt": "9.1.1", + "tas-client": "^0.0.950", "v8-inspect-profiler": "^0.0.20", "vscode-nsfw": "1.2.8", "vscode-oniguruma": "1.3.1", @@ -69,10 +70,10 @@ "vscode-ripgrep": "^1.8.0", "vscode-sqlite3": "4.0.10", "vscode-textmate": "5.2.0", - "xterm": "4.8.1", + "xterm": "4.9.0-beta.8", "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", - "xterm-addon-webgl": "0.7.0", + "xterm-addon-webgl": "0.8.0", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, @@ -108,7 +109,7 @@ "css-loader": "^3.2.0", "debounce": "^1.0.0", "deemon": "^1.4.0", - "electron": "9.1.0", + "electron": "9.2.0", "eslint": "6.8.0", "eslint-plugin-jsdoc": "^19.1.0", "event-stream": "3.3.4", @@ -163,7 +164,7 @@ "source-map": "^0.4.4", "style-loader": "^1.0.0", "ts-loader": "^4.4.2", - "typescript": "^4.0.0-dev.20200722", + "typescript": "^4.0.1-rc", "typescript-formatter": "7.1.0", "underscore": "^1.8.2", "vinyl": "^2.0.0", diff --git a/product.json b/product.json index 94b2c9862cc..efbb04d8b55 100644 --- a/product.json +++ b/product.json @@ -25,12 +25,13 @@ "extensionAllowedProposedApi": [ "ms-vscode.vscode-js-profile-flame", "ms-vscode.vscode-js-profile-table", - "ms-vscode.references-view" + "ms-vscode.references-view", + "ms-vscode.github-browser" ], "builtInExtensions": [ { "name": "ms-vscode.node-debug", - "version": "1.44.7", + "version": "1.44.9", "repo": "https://github.com/Microsoft/vscode-node-debug", "metadata": { "id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6", @@ -60,7 +61,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.61", + "version": "0.0.62", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", @@ -90,7 +91,7 @@ }, { "name": "ms-vscode.js-debug", - "version": "1.48.0", + "version": "1.48.1", "repo": "https://github.com/Microsoft/vscode-js-debug", "metadata": { "id": "25629058-ddac-4e17-abba-74678e126c5d", @@ -118,5 +119,22 @@ "publisherDisplayName": "Microsoft" } } + ], + "webBuiltInExtensions": [ + { + "name": "ms-vscode.github-browser", + "version": "0.0.2", + "repo": "https://github.com/Microsoft/vscode-github-browser", + "metadata": { + "id": "c1bcff4b-4ecb-466e-b8f6-b02788b5fb5a", + "publisherId": { + "publisherId": "5f5636e7-69ed-4afe-b5d6-8d231fb3d3ee", + "publisherName": "ms-vscode", + "displayName": "Microsoft", + "flags": "verified" + }, + "publisherDisplayName": "Microsoft" + } + } ] } diff --git a/remote/package.json b/remote/package.json index a31fcd4a1a3..c10fbe792c2 100644 --- a/remote/package.json +++ b/remote/package.json @@ -20,10 +20,10 @@ "vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.8.0", "vscode-textmate": "5.2.0", - "xterm": "4.8.1", + "xterm": "4.9.0-beta.8", "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", - "xterm-addon-webgl": "0.7.0", + "xterm-addon-webgl": "0.8.0", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index 26dfd2b30bd..de712cfdeb3 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -7,9 +7,9 @@ "semver-umd": "^5.5.7", "vscode-oniguruma": "1.3.1", "vscode-textmate": "5.2.0", - "xterm": "4.8.1", + "xterm": "4.9.0-beta.8", "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", - "xterm-addon-webgl": "0.7.0" + "xterm-addon-webgl": "0.8.0" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index da501df1475..15fb0958eea 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -37,12 +37,12 @@ xterm-addon-unicode11@0.2.0: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0.tgz#9ed0c482b353908bba27778893ca80823382737c" integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q== -xterm-addon-webgl@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0.tgz#a13732ac937170e53ce02ec91963da042c80614b" - integrity sha512-PMWLgccAF31GulCYkQxIA8qwMI4q4UbRi5O/zwMnSJWBozB0yy84lX31ZhJeJhcrlEn1Vpcd+OUGPE8Z1hBjnw== +xterm-addon-webgl@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f" + integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ== -xterm@4.8.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.8.1.tgz#155a1729a43e1a89b406524e22c5634339e39ca1" - integrity sha512-ax91ny4tI5eklqIfH79OUSGE2PUX2rGbwONmB6DfqpyhSZO8/cf++sqiaMWEVCMjACyMfnISW7C3gGMoNvNolQ== +xterm@4.9.0-beta.8: + version "4.9.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805" + integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA== diff --git a/remote/yarn.lock b/remote/yarn.lock index 18f4de33810..499dc73ca5c 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -440,15 +440,15 @@ xterm-addon-unicode11@0.2.0: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0.tgz#9ed0c482b353908bba27778893ca80823382737c" integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q== -xterm-addon-webgl@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0.tgz#a13732ac937170e53ce02ec91963da042c80614b" - integrity sha512-PMWLgccAF31GulCYkQxIA8qwMI4q4UbRi5O/zwMnSJWBozB0yy84lX31ZhJeJhcrlEn1Vpcd+OUGPE8Z1hBjnw== +xterm-addon-webgl@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f" + integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ== -xterm@4.8.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.8.1.tgz#155a1729a43e1a89b406524e22c5634339e39ca1" - integrity sha512-ax91ny4tI5eklqIfH79OUSGE2PUX2rGbwONmB6DfqpyhSZO8/cf++sqiaMWEVCMjACyMfnISW7C3gGMoNvNolQ== +xterm@4.9.0-beta.8: + version "4.9.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805" + integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA== yauzl@^2.9.2: version "2.10.0" diff --git a/resources/serverless/callback.html b/resources/web/callback.html similarity index 100% rename from resources/serverless/callback.html rename to resources/web/callback.html diff --git a/resources/serverless/code-web.js b/resources/web/code-web.js similarity index 75% rename from resources/serverless/code-web.js rename to resources/web/code-web.js index 998d88b8842..bfe3f9f9a21 100644 --- a/resources/serverless/code-web.js +++ b/resources/web/code-web.js @@ -16,19 +16,25 @@ const opn = require('opn'); const minimist = require('minimist'); const fancyLog = require('fancy-log'); const ansiColors = require('ansi-colors'); +const remote = require('gulp-remote-retry-src'); +const vfs = require('vinyl-fs'); const extensions = require('../../build/lib/extensions'); const APP_ROOT = path.join(__dirname, '..', '..'); const BUILTIN_EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions'); const BUILTIN_MARKETPLACE_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInExtensions'); +const WEB_DEV_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInWebDevExtensions'); const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench', 'workbench-dev.html'); +const WEB_PLAYGROUND_VERSION = '0.0.1'; + const args = minimist(process.argv, { boolean: [ 'no-launch', 'help', - 'verbose' + 'verbose', + 'wrap-iframe' ], string: [ 'scheme', @@ -43,6 +49,7 @@ if (args.help) { console.log( 'yarn web [options]\n' + ' --no-launch Do not open VSCode web in the browser\n' + + ' --wrap-iframe Wrap the Web Worker Extension Host in an iframe\n' + ' --scheme Protocol (https or http)\n' + ' --host Remote host\n' + ' --port Remote/Local port\n' + @@ -64,56 +71,77 @@ const AUTHORITY = process.env.VSCODE_AUTHORITY || `${HOST}:${PORT}`; const exists = (path) => util.promisify(fs.exists)(path); const readFile = (path) => util.promisify(fs.readFile)(path); -const readdir = (path) => util.promisify(fs.readdir)(path); -const readdirWithFileTypes = (path) => util.promisify(fs.readdir)(path, { withFileTypes: true }); async function getBuiltInExtensionInfos() { - const extensions = []; + const allExtensions = []; /** @type {Object.} */ const locations = {}; - for (const extensionsRoot of [BUILTIN_EXTENSIONS_ROOT, BUILTIN_MARKETPLACE_EXTENSIONS_ROOT]) { - if (await exists(extensionsRoot)) { - const children = await readdirWithFileTypes(extensionsRoot); - await Promise.all(children.map(async child => { - if (child.isDirectory()) { - const extensionPath = path.join(extensionsRoot, child.name); - const info = await getBuiltInExtensionInfo(extensionPath); - if (info) { - extensions.push(info); - locations[path.basename(extensionPath)] = extensionPath; - } - } - })); + const [localExtensions, marketplaceExtensions, webDevExtensions] = await Promise.all([ + extensions.scanBuiltinExtensions(BUILTIN_EXTENSIONS_ROOT), + extensions.scanBuiltinExtensions(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT), + ensureWebDevExtensions().then(() => extensions.scanBuiltinExtensions(WEB_DEV_EXTENSIONS_ROOT)) + ]); + for (const ext of localExtensions) { + allExtensions.push(ext); + locations[ext.extensionPath] = path.join(BUILTIN_EXTENSIONS_ROOT, ext.extensionPath); + } + for (const ext of marketplaceExtensions) { + allExtensions.push(ext); + locations[ext.extensionPath] = path.join(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT, ext.extensionPath); + } + for (const ext of webDevExtensions) { + allExtensions.push(ext); + locations[ext.extensionPath] = path.join(WEB_DEV_EXTENSIONS_ROOT, ext.extensionPath); + } + for (const ext of allExtensions) { + if (ext.packageJSON.browser) { + let mainFilePath = path.join(locations[ext.extensionPath], ext.packageJSON.browser); + if (path.extname(mainFilePath) !== '.js') { + mainFilePath += '.js'; + } + if (!await exists(mainFilePath)) { + fancyLog(`${ansiColors.red('Error')}: Could not find ${mainFilePath}. Use ${ansiColors.cyan('yarn watch-web')} to build the built-in extensions.`); + } } } - return { extensions, locations }; + return { extensions: allExtensions, locations }; } -async function getBuiltInExtensionInfo(extensionPath) { - const packageJSON = await getExtensionPackageJSON(extensionPath); - if (!packageJSON) { - return undefined; - } - const builtInExtensionPath = path.basename(extensionPath); +async function ensureWebDevExtensions() { - let children = []; - try { - children = await readdir(extensionPath); - } catch (error) { - console.log(`Can not read extension folder ${extensionPath}: ${error}`); - return; + // Playground (https://github.com/microsoft/vscode-web-playground) + const webDevPlaygroundRoot = path.join(WEB_DEV_EXTENSIONS_ROOT, 'vscode-web-playground'); + const webDevPlaygroundExists = await exists(webDevPlaygroundRoot); + + let downloadPlayground = false; + if (webDevPlaygroundExists) { + try { + const webDevPlaygroundPackageJson = JSON.parse(((await readFile(path.join(webDevPlaygroundRoot, 'package.json'))).toString())); + if (webDevPlaygroundPackageJson.version !== WEB_PLAYGROUND_VERSION) { + downloadPlayground = true; + } + } catch (error) { + downloadPlayground = true; + } + } else { + downloadPlayground = true; + } + + if (downloadPlayground) { + if (args.verbose) { + fancyLog(`${ansiColors.magenta('Web Development extensions')}: Downloading vscode-web-playground to ${webDevPlaygroundRoot}`); + } + await new Promise((resolve, reject) => { + remote(['package.json', 'dist/extension.js', 'dist/extension.js.map'], { + base: 'https://raw.githubusercontent.com/microsoft/vscode-web-playground/main/' + }).pipe(vfs.dest(webDevPlaygroundRoot)).on('end', resolve).on('error', reject); + }); + } else { + if (args.verbose) { + fancyLog(`${ansiColors.magenta('Web Development extensions')}: Using existing vscode-web-playground in ${webDevPlaygroundRoot}`); + } } - const readme = children.find(child => /^readme(\.txt|\.md|)$/i.test(child)); - const changelog = children.find(child => /^changelog(\.txt|\.md|)$/i.test(child)); - const packageJSONNLS = children.find(child => /^package.nls.json$/i.test(child)); - return { - extensionPath: builtInExtensionPath, - packageJSON, - packageNLSPath: packageJSONNLS ? `${builtInExtensionPath}/${packageJSONNLS}` : undefined, - readmePath: readme ? `${builtInExtensionPath}/${readme}` : undefined, - changelogPath: changelog ? `${builtInExtensionPath}/${changelog}` : undefined - }; } async function getDefaultExtensionInfos() { @@ -124,7 +152,7 @@ async function getDefaultExtensionInfos() { let extensionArg = args['extension']; if (!extensionArg) { - return { extensions, locations } + return { extensions, locations }; } const extensionPaths = Array.isArray(extensionArg) ? extensionArg : [extensionArg]; @@ -153,19 +181,6 @@ async function getExtensionPackageJSON(extensionPath) { return; // unsupported } - if (packageJSON.browser) { - packageJSON.main = packageJSON.browser; - - let mainFilePath = path.join(extensionPath, packageJSON.browser); - if (path.extname(mainFilePath) !== '.js') { - mainFilePath += '.js'; - } - if (!await exists(mainFilePath)) { - fancyLog(`${ansiColors.yellow('Warning')}: Could not find ${mainFilePath}. Use ${ansiColors.cyan('yarn gulp watch-web')} to build the built-in extensions.`); - } - } - packageJSON.extensionKind = ['web']; // enable for Web - const packageNLSPath = path.join(extensionPath, 'package.nls.json'); const packageNLSExists = await exists(packageNLSPath); if (packageNLSExists) { @@ -213,10 +228,6 @@ const server = http.createServer((req, res) => { // default extension requests return handleExtension(req, res, parsedUrl); } - if (/^\/builtin-extension\//.test(pathname)) { - // built-in extension requests - return handleBuiltInExtension(req, res, parsedUrl); - } if (pathname === '/') { // main web return handleRoot(req, res); @@ -253,7 +264,18 @@ server.on('error', err => { * @param {import('http').ServerResponse} res * @param {import('url').UrlWithParsedQuery} parsedUrl */ -function handleStatic(req, res, parsedUrl) { +async function handleStatic(req, res, parsedUrl) { + + if (/^\/static\/extensions\//.test(parsedUrl.pathname)) { + const relativePath = decodeURIComponent(parsedUrl.pathname.substr('/static/extensions/'.length)); + const filePath = getExtensionFilePath(relativePath, (await builtInExtensionsPromise).locations); + if (!filePath) { + return serveError(req, res, 400, `Bad request.`); + } + return serveFile(req, res, filePath, { + 'Access-Control-Allow-Origin': '*' + }); + } // Strip `/static/` from the path const relativeFilePath = path.normalize(decodeURIComponent(parsedUrl.pathname.substr('/static/'.length))); @@ -273,22 +295,9 @@ async function handleExtension(req, res, parsedUrl) { if (!filePath) { return serveError(req, res, 400, `Bad request.`); } - return serveFile(req, res, filePath); -} - -/** - * @param {import('http').IncomingMessage} req - * @param {import('http').ServerResponse} res - * @param {import('url').UrlWithParsedQuery} parsedUrl - */ -async function handleBuiltInExtension(req, res, parsedUrl) { - // Strip `/builtin-extension/` from the path - const relativePath = decodeURIComponent(parsedUrl.pathname.substr('/builtin-extension/'.length)); - const filePath = getExtensionFilePath(relativePath, (await builtInExtensionsPromise).locations); - if (!filePath) { - return serveError(req, res, 400, `Bad request.`); - } - return serveFile(req, res, filePath); + return serveFile(req, res, filePath, { + 'Access-Control-Allow-Origin': '*' + }); } /** @@ -309,7 +318,8 @@ async function handleRoot(req, res) { } const [owner, repo, ...branch] = gh.split('/', 3); - folderUri = { scheme: 'github', authority: branch.join('/') || 'HEAD', path: `/${owner}/${repo}` }; + const ref = branch.join('/'); + folderUri = { scheme: 'github', authority: `${owner}+${repo}${ref ? `+${ref}` : ''}`, path: '/' }; } else { let cs = qs.get('cs'); if (cs) { @@ -318,7 +328,8 @@ async function handleRoot(req, res) { } const [owner, repo, ...branch] = cs.split('/'); - folderUri = { scheme: 'codespace', authority: branch.join('/') || 'HEAD', path: `/${owner}/${repo}` }; + const ref = branch.join('/'); + folderUri = { scheme: 'codespace', authority: `${owner}+${repo}${ref ? `+${ref}` : ''}`, path: '/' }; } } } @@ -331,14 +342,16 @@ async function handleRoot(req, res) { fancyLog(`${ansiColors.magenta('Additional extensions')}: ${staticExtensions.map(e => path.basename(e.extensionLocation.path)).join(', ') || 'None'}`); } - const webConfigJSON = escapeAttribute(JSON.stringify({ + const webConfigJSON = { folderUri: folderUri, staticExtensions, - builtinExtensionsServiceUrl: `${SCHEME}://${AUTHORITY}/builtin-extension` - })); + }; + if (args['wrap-iframe']) { + webConfigJSON._wrapWebWorkerExtHostInIframe = true; + } const data = (await readFile(WEB_MAIN)).toString() - .replace('{{WORKBENCH_WEB_CONFIGURATION}}', () => webConfigJSON) // use a replace function to avoid that regexp replace patterns ($&, $0, ...) are applied + .replace('{{WORKBENCH_WEB_CONFIGURATION}}', () => escapeAttribute(JSON.stringify(webConfigJSON))) // use a replace function to avoid that regexp replace patterns ($&, $0, ...) are applied .replace('{{WORKBENCH_BUILTIN_EXTENSIONS}}', () => escapeAttribute(JSON.stringify(builtInExtensions))) .replace('{{WEBVIEW_ENDPOINT}}', '') .replace('{{REMOTE_USER_DATA_URI}}', ''); @@ -384,7 +397,7 @@ async function handleCallback(req, res, parsedUrl) { // add to map of known callbacks mapCallbackUriToRequestId.set(requestId, JSON.stringify({ scheme: vscodeScheme || 'code-oss', authority: vscodeAuthority, path: vscodePath, query, fragment: vscodeFragment })); - return serveFile(req, res, path.join(APP_ROOT, 'resources', 'serverless', 'callback.html'), { 'Content-Type': 'text/html' }); + return serveFile(req, res, path.join(APP_ROOT, 'resources', 'web', 'callback.html'), { 'Content-Type': 'text/html' }); } /** diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index 9f029e5522a..d86b6e0574a 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -37,7 +37,7 @@ else fi if [ $IN_WSL = true ]; then - export WSLENV=ELECTRON_RUN_AS_NODE/w:$WSLENV + export WSLENV="ELECTRON_RUN_AS_NODE/w:$WSLENV" CLI=$(wslpath -m "$VSCODE_PATH/resources/app/out/cli.js") # use the Remote WSL extension if installed diff --git a/scripts/code-cli.bat b/scripts/code-cli.bat index a07ccc96bf6..2e4e34ff32e 100644 --- a/scripts/code-cli.bat +++ b/scripts/code-cli.bat @@ -5,27 +5,17 @@ title VSCode Dev pushd %~dp0\.. -:: Node modules -if not exist node_modules call yarn +:: Get electron, compile, built-in extensions +if "%VSCODE_SKIP_PRELAUNCH%"=="" node build/lib/preLaunch.js 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 -node build\lib\electron.js -if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron - :: Manage built-in extensions if "%1"=="--builtin" goto builtin -:: Sync built-in extensions -node build\lib\builtInExtensions.js - -:: Build -if not exist out yarn compile - :: Configuration set ELECTRON_RUN_AS_NODE=1 set NODE_ENV=development diff --git a/scripts/code-cli.sh b/scripts/code-cli.sh index e4fa552e642..a792c08532e 100755 --- a/scripts/code-cli.sh +++ b/scripts/code-cli.sh @@ -18,11 +18,10 @@ function code() { CODE=".build/electron/$NAME" fi - # Node modules - test -d node_modules || yarn - - # Get electron - yarn electron + # Get electron, compile, built-in extensions + if [[ -z "${VSCODE_SKIP_PRELAUNCH}" ]]; then + node build/lib/preLaunch.js + fi # Manage built-in extensions if [[ "$1" == "--builtin" ]]; then @@ -30,12 +29,6 @@ function code() { return fi - # Sync built-in extensions - node build/lib/builtInExtensions.js - - # Build - test -d out || yarn compile - ELECTRON_RUN_AS_NODE=1 \ NODE_ENV=development \ VSCODE_DEV=1 \ diff --git a/scripts/code.bat b/scripts/code.bat index c4c1cc7c057..7ef1fd33fe0 100644 --- a/scripts/code.bat +++ b/scripts/code.bat @@ -5,26 +5,17 @@ title VSCode Dev pushd %~dp0\.. -:: Node modules -if not exist node_modules call yarn +:: Get electron, compile, built-in extensions +if "%VSCODE_SKIP_PRELAUNCH%"=="" node build/lib/preLaunch.js 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%" -:: Get electron -call yarn electron - :: Manage built-in extensions if "%1"=="--builtin" goto builtin -:: Sync built-in extensions -node build\lib\builtInExtensions.js - -:: Build -if not exist out yarn compile - :: Configuration set NODE_ENV=development set VSCODE_DEV=1 diff --git a/scripts/code.sh b/scripts/code.sh index 390aa4b201d..b19cc0df9ff 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -24,11 +24,10 @@ function code() { CODE=".build/electron/$NAME" fi - # Node modules - test -d node_modules || yarn - - # Get electron - yarn electron + # Get electron, compile, built-in extensions + if [[ -z "${VSCODE_SKIP_PRELAUNCH}" ]]; then + node build/lib/preLaunch.js + fi # Manage built-in extensions if [[ "$1" == "--builtin" ]]; then @@ -36,12 +35,6 @@ function code() { return fi - # Sync built-in extensions - node build/lib/builtInExtensions.js - - # Build - test -d out || yarn compile - # Configuration export NODE_ENV=development export VSCODE_DEV=1 diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 4450d838c8c..5a493b0b1c5 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -23,6 +23,7 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( compile-extension:vscode-colorize-tests^ compile-extension:markdown-language-features^ compile-extension:typescript-language-features^ + compile-extension:vscode-custom-editor-tests^ compile-extension:vscode-notebook-tests^ compile-extension:emmet^ compile-extension:css-language-features-server^ @@ -71,8 +72,11 @@ mkdir %GITWORKSPACE% call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test --enable-proposed-api=vscode.git --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -:: Tests in commonJS (HTML, CSS, JSON language server tests...) -call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js +:: Tests in commonJS (CSS, HTML) +call %~dp0\node-electron.bat %~dp0\..\extensions\css-language-features/server/test/index.js +if %errorlevel% neq 0 exit /b %errorlevel% + +call %~dp0\node-electron.bat %~dp0\..\extensions\html-language-features/server/test/index.js if %errorlevel% neq 0 exit /b %errorlevel% rmdir /s /q %VSCODEUSERDATADIR% diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 3288a8c0516..6856ebd525f 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -27,6 +27,7 @@ else # and the build bundles extensions into .build webpacked yarn gulp compile-extension:vscode-api-tests \ compile-extension:vscode-colorize-tests \ + compile-extension:vscode-custom-editor-tests \ compile-extension:vscode-notebook-tests \ compile-extension:markdown-language-features \ compile-extension:typescript-language-features \ @@ -58,7 +59,7 @@ fi "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR -# Tests in commonJS +# Tests in commonJS (CSS, HTML) cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 76c00585ad8..9d1ddc5a957 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -23,6 +23,7 @@ }(this, function () { const preloadGlobals = globals(); const sandbox = preloadGlobals.context.sandbox; + const webFrame = preloadGlobals.webFrame; const safeProcess = sandbox ? preloadGlobals.process : process; /** @@ -35,6 +36,7 @@ /** * // configuration: INativeWindowConfiguration * @type {{ + * zoomLevel?: number, * extensionDevelopmentPath?: string[], * extensionTestsPath?: string, * userEnv?: { [key: string]: string | undefined }, @@ -43,6 +45,12 @@ * }} */ const configuration = JSON.parse(args['config'] || '{}') || {}; + // Apply zoom level early to avoid glitches + const zoomLevel = configuration.zoomLevel; + if (typeof zoomLevel === 'number' && zoomLevel !== 0) { + webFrame.setZoomLevel(zoomLevel); + } + // Error handler safeProcess.on('uncaughtException', function (error) { onUnexpectedError(error, enableDeveloperTools); diff --git a/src/main.js b/src/main.js index 9a49d06217a..9d68c984c66 100644 --- a/src/main.js +++ b/src/main.js @@ -313,17 +313,6 @@ function createDefaultArgvConfigSync(argvConfigPath) { fs.mkdirSync(argvConfigPathDirname); } - // Migrate over legacy locale - const localeConfigPath = path.join(userDataPath, 'User', 'locale.json'); - const legacyLocale = getLegacyUserDefinedLocaleSync(localeConfigPath); - if (legacyLocale) { - try { - fs.unlinkSync(localeConfigPath); - } catch (error) { - //ignore - } - } - // Default argv content const defaultArgvConfigContent = [ '// This configuration file allows you to pass permanent command line arguments to VS Code.', @@ -340,19 +329,10 @@ function createDefaultArgvConfigSync(argvConfigPath) { '', ' // Enabled by default by VS Code to resolve color issues in the renderer', ' // See https://github.com/Microsoft/vscode/issues/51791 for details', - ' "disable-color-correct-rendering": true' + ' "disable-color-correct-rendering": true', + '}' ]; - if (legacyLocale) { - defaultArgvConfigContent[defaultArgvConfigContent.length - 1] = `${defaultArgvConfigContent[defaultArgvConfigContent.length - 1]},`; // append trailing "," - - defaultArgvConfigContent.push(''); - defaultArgvConfigContent.push(' // Display language of VS Code'); - defaultArgvConfigContent.push(` "locale": "${legacyLocale}"`); - } - - defaultArgvConfigContent.push('}'); - // Create initial argv.json with default content fs.writeFileSync(argvConfigPath, defaultArgvConfigContent.join('\n')); } catch (error) { @@ -610,19 +590,4 @@ function getUserDefinedLocale(argvConfig) { return argvConfig.locale && typeof argvConfig.locale === 'string' ? argvConfig.locale.toLowerCase() : undefined; } -/** - * @param {string} localeConfigPath - * @returns {string | undefined} - */ -function getLegacyUserDefinedLocaleSync(localeConfigPath) { - try { - const content = stripComments(fs.readFileSync(localeConfigPath).toString()); - - const value = JSON.parse(content).locale; - return value && typeof value === 'string' ? value.toLowerCase() : undefined; - } catch (error) { - // ignore - } -} - //#endregion diff --git a/src/tsconfig.base.json b/src/tsconfig.base.json index 19165d97b72..a4c419cf5f4 100644 --- a/src/tsconfig.base.json +++ b/src/tsconfig.base.json @@ -5,6 +5,7 @@ "experimentalDecorators": true, "noImplicitReturns": true, "noUnusedLocals": true, + "allowUnreachableCode": false, "strict": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", diff --git a/src/typings/node.processEnv-ext.d.ts b/src/typings/node.processEnv-ext.d.ts deleted file mode 100644 index fec557ff2a7..00000000000 --- a/src/typings/node.processEnv-ext.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare namespace NodeJS { - - export interface Process { - - /** - * The lazy enviroment is a promise that resolves to `process.env` - * once the process is resolved. The use-case is VS Code running - * on Linux/macOS when being launched via a launcher. Then the env - * (as defined in .bashrc etc) isn't properly set and needs to be - * resolved lazy. - */ - lazyEnv: Thenable | undefined; - } -} diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index d5622349ff0..29490d6fc1e 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -23,6 +23,9 @@ export function clearNode(node: HTMLElement): void { } } +/** + * @deprecated use `node.remove()` instead + */ export function removeNode(node: HTMLElement): void { if (node.parentNode) { node.parentNode.removeChild(node); @@ -749,6 +752,16 @@ export function getShadowRoot(domNode: Node): ShadowRoot | null { return isShadowRoot(domNode) ? domNode : null; } +export function getActiveElement(): Element | null { + let result = document.activeElement; + + while (result?.shadowRoot) { + result = result.shadowRoot.activeElement; + } + + return result; +} + export function createStyleSheet(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLStyleElement { let style = document.createElement('style'); style.type = 'text/css'; @@ -994,7 +1007,7 @@ export function prepend(parent: HTMLElement, child: T): T { return child; } -const SELECTOR_REGEX = /([\w\-]+)?(#([\w\-]+))?((.([\w\-]+))*)/; +const SELECTOR_REGEX = /([\w\-]+)?(#([\w\-]+))?((\.([\w\-]+))*)/; export enum Namespace { HTML = 'http://www.w3.org/1999/xhtml', diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index e79f159100b..48ead97d48f 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -17,6 +17,7 @@ import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { renderCodicons, markdownEscapeEscapedCodicons } from 'vs/base/common/codicons'; import { resolvePath } from 'vs/base/common/resources'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; export interface MarkedOptions extends marked.MarkedOptions { baseUrl?: never; @@ -171,25 +172,32 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende const actionHandler = options.actionHandler; if (actionHandler) { - actionHandler.disposeables.add(DOM.addStandardDisposableListener(element, 'click', event => { - let target: HTMLElement | null = event.target; - if (target.tagName !== 'A') { - target = target.parentElement; - if (!target || target.tagName !== 'A') { + [DOM.EventType.CLICK, DOM.EventType.AUXCLICK].forEach(event => { + actionHandler.disposeables.add(DOM.addDisposableListener(element, event, (e: MouseEvent) => { + const mouseEvent = new StandardMouseEvent(e); + if (!mouseEvent.leftButton && !mouseEvent.middleButton) { return; } - } - try { - const href = target.dataset['href']; - if (href) { - actionHandler.callback(href, event); + + let target: HTMLElement | null = mouseEvent.target; + if (target.tagName !== 'A') { + target = target.parentElement; + if (!target || target.tagName !== 'A') { + return; + } } - } catch (err) { - onUnexpectedError(err); - } finally { - event.preventDefault(); - } - })); + try { + const href = target.dataset['href']; + if (href) { + actionHandler.callback(href, mouseEvent); + } + } catch (err) { + onUnexpectedError(err); + } finally { + mouseEvent.preventDefault(); + } + })); + }); } // Use our own sanitizer so that we can let through only spans. diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 54e8b94d025..b7916bf107d 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -137,17 +137,9 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, e => { DOM.EventHelper.stop(e, true); - // See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard - // > Writing to the clipboard - // > You can use the "cut" and "copy" commands without any special - // permission if you are using them in a short-lived event handler - // for a user action (for example, a click handler). - // => to get the Copy and Paste context menu actions working on Firefox, - // there should be no timeout here - if (this.options && this.options.isMenu) { - this.onClick(e); - } else { + // menus do not use the click event + if (!(this.options && this.options.isMenu)) { platform.setImmediate(() => this.onClick(e)); } })); diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 0044d786b6a..aef1d1c1e1d 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -173,7 +173,7 @@ export class ActionBar extends Disposable implements IActionRunner { this.focusTracker = this._register(DOM.trackFocus(this.domNode)); this._register(this.focusTracker.onDidBlur(() => { - if (document.activeElement === this.domNode || !DOM.isAncestor(document.activeElement, this.domNode)) { + if (DOM.getActiveElement() === this.domNode || !DOM.isAncestor(DOM.getActiveElement(), this.domNode)) { this._onDidBlur.fire(); this.focusedItem = undefined; } @@ -214,7 +214,7 @@ export class ActionBar extends Disposable implements IActionRunner { private updateFocusedItem(): void { for (let i = 0; i < this.actionsList.children.length; i++) { const elem = this.actionsList.children[i]; - if (DOM.isAncestor(document.activeElement, elem)) { + if (DOM.isAncestor(DOM.getActiveElement(), elem)) { this.focusedItem = i; break; } @@ -285,6 +285,10 @@ export class ActionBar extends Disposable implements IActionRunner { index++; } }); + if (this.focusedItem) { + // After a clear actions might be re-added to simply toggle some actions. We should preserve focus #97128 + this.focus(this.focusedItem); + } } getWidth(index: number): number { diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 0863191afd2..60a97219140 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -156,7 +156,7 @@ export class ContextView extends Disposable { if (this.useShadowDOM) { this.shadowRootHostElement = DOM.$('.shadow-root-host'); this.container.appendChild(this.shadowRootHostElement); - this.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'closed' }); + this.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = `