diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 4a04784b892..51e7f366043 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - name: Question - url: https://stackoverflow.com/questions/tagged/visual-studio-code + url: https://stackoverflow.com/questions/tagged/visual-studio-code about: Please ask and answer questions here. diff --git a/.github/calendar.yml b/.github/calendar.yml index f149579600b..c1b5a256980 100644 --- a/.github/calendar.yml +++ b/.github/calendar.yml @@ -1,37 +1,37 @@ { - '2018-01-29 18:00, US/Pacific': 'endgame', - '2018-02-07 12:00, US/Pacific': 'release', # 1.20.0 - '2018-02-12 12:00, US/Pacific': 'development', - '2018-02-14 16:00, Europe/Zurich': 'release', # 1.20.1 - '2018-02-19 16:00, Europe/Zurich': 'development', - '2018-02-26 18:00, US/Pacific': 'endgame', - '2018-03-07 12:00, US/Pacific': 'release', # 1.21.0 - '2018-03-12 12:00, US/Pacific': 'development', - '2018-03-15 12:00, US/Pacific': 'release', # 1.21.1 - '2018-03-20 12:00, US/Pacific': 'development', - '2018-03-26 18:00, US/Pacific': 'endgame', - '2018-04-06 18:00, US/Pacific': 'release', # 1.22.1 - '2018-04-11 18:00, US/Pacific': 'development', - '2018-04-12 12:00, US/Pacific': 'release', # 1.22.2 - '2018-04-17 12:00, US/Pacific': 'development', - '2018-04-23 18:00, US/Pacific': 'endgame', - '2018-05-03 12:00, US/Pacific': 'release', # 1.23.0 - '2018-05-08 12:00, US/Pacific': 'development', - '2018-05-10 12:00, US/Pacific': 'release', # 1.23.1 - '2018-05-15 12:00, US/Pacific': 'development', - '2018-05-28 18:00, US/Pacific': 'endgame', + "2018-01-29 18:00, US/Pacific": "endgame", + "2018-02-07 12:00, US/Pacific": "release", # 1.20.0 + "2018-02-12 12:00, US/Pacific": "development", + "2018-02-14 16:00, Europe/Zurich": "release", # 1.20.1 + "2018-02-19 16:00, Europe/Zurich": "development", + "2018-02-26 18:00, US/Pacific": "endgame", + "2018-03-07 12:00, US/Pacific": "release", # 1.21.0 + "2018-03-12 12:00, US/Pacific": "development", + "2018-03-15 12:00, US/Pacific": "release", # 1.21.1 + "2018-03-20 12:00, US/Pacific": "development", + "2018-03-26 18:00, US/Pacific": "endgame", + "2018-04-06 18:00, US/Pacific": "release", # 1.22.1 + "2018-04-11 18:00, US/Pacific": "development", + "2018-04-12 12:00, US/Pacific": "release", # 1.22.2 + "2018-04-17 12:00, US/Pacific": "development", + "2018-04-23 18:00, US/Pacific": "endgame", + "2018-05-03 12:00, US/Pacific": "release", # 1.23.0 + "2018-05-08 12:00, US/Pacific": "development", + "2018-05-10 12:00, US/Pacific": "release", # 1.23.1 + "2018-05-15 12:00, US/Pacific": "development", + "2018-05-28 18:00, US/Pacific": "endgame", # 'release' not needed anymore, return to 'development' after releasing. - '2018-06-06 12:00, US/Pacific': 'development', # 1.24.0 released - '2018-06-25 18:00, US/Pacific': 'endgame', - '2018-07-05 12:00, US/Pacific': 'development', # 1.25.0 released - '2018-07-30 18:00, US/Pacific': 'endgame', - '2018-08-13 12:00, US/Pacific': 'development', # 1.26.0 released - '2018-08-27 18:00, US/Pacific': 'endgame', - '2018-09-05 12:00, US/Pacific': 'development', # 1.27.0 released - '2018-09-24 18:00, US/Pacific': 'endgame', - '2018-10-08 09:00, US/Pacific': 'development', # 1.28.0 released - '2018-10-29 18:00, US/Pacific': 'endgame', - '2018-11-12 11:00, US/Pacific': 'development', # 1.29.0 released - '2018-12-03 18:00, US/Pacific': 'endgame', - '2018-12-12 13:00, US/Pacific': 'development', # 1.30.0 released + "2018-06-06 12:00, US/Pacific": "development", # 1.24.0 released + "2018-06-25 18:00, US/Pacific": "endgame", + "2018-07-05 12:00, US/Pacific": "development", # 1.25.0 released + "2018-07-30 18:00, US/Pacific": "endgame", + "2018-08-13 12:00, US/Pacific": "development", # 1.26.0 released + "2018-08-27 18:00, US/Pacific": "endgame", + "2018-09-05 12:00, US/Pacific": "development", # 1.27.0 released + "2018-09-24 18:00, US/Pacific": "endgame", + "2018-10-08 09:00, US/Pacific": "development", # 1.28.0 released + "2018-10-29 18:00, US/Pacific": "endgame", + "2018-11-12 11:00, US/Pacific": "development", # 1.29.0 released + "2018-12-03 18:00, US/Pacific": "endgame", + "2018-12-12 13:00, US/Pacific": "development", # 1.30.0 released } diff --git a/.github/commands.yml b/.github/commands.yml index 64fdf683bfe..5073658e526 100644 --- a/.github/commands.yml +++ b/.github/commands.yml @@ -1,12 +1,13 @@ { - perform: true, - commands: [ - { - type: 'comment', - name: 'findDuplicates', - allowUsers: ['cleidigh', 'usernamehw', 'gjsjohnmurray', 'IllusionMH'], - action: 'comment', - comment: "Potential duplicates:\n${potentialDuplicates}" - } - ] + perform: true, + commands: + [ + { + type: "comment", + name: "findDuplicates", + allowUsers: ["cleidigh", "usernamehw", "gjsjohnmurray", "IllusionMH"], + action: "comment", + comment: "Potential duplicates:\n${potentialDuplicates}", + }, + ], } diff --git a/.github/endgame/insiders.yml b/.github/endgame/insiders.yml index f11bd611cb2..4996474f4d2 100644 --- a/.github/endgame/insiders.yml +++ b/.github/endgame/insiders.yml @@ -1,6 +1,6 @@ { - insidersLabel: 'insiders', - insidersColor: '006b75', - action: 'add', - perform: true -} \ No newline at end of file + insidersLabel: "insiders", + insidersColor: "006b75", + action: "add", + perform: true, +} diff --git a/.github/insiders.yml b/.github/insiders.yml index e9a49ce7858..ab59e873bee 100644 --- a/.github/insiders.yml +++ b/.github/insiders.yml @@ -1,6 +1,6 @@ { - insidersLabel: 'insiders', - insidersColor: '006b75', - action: 'remove', - perform: true -} \ No newline at end of file + insidersLabel: "insiders", + insidersColor: "006b75", + action: "remove", + perform: true, +} diff --git a/.github/similarity.yml b/.github/similarity.yml index cd51cd2da64..cb00a4c9a8e 100644 --- a/.github/similarity.yml +++ b/.github/similarity.yml @@ -1,5 +1,5 @@ { - perform: true, - whenCreatedByTeam: false, - comment: "(Experimental duplicate detection)\nThanks for submitting this issue. Please also check if it is already covered by an existing one, like:\n${potentialDuplicates}" + perform: true, + whenCreatedByTeam: false, + comment: "(Experimental duplicate detection)\nThanks for submitting this issue. Please also check if it is already covered by an existing one, like:\n${potentialDuplicates}", } diff --git a/.github/workflows/author-verified.yml b/.github/workflows/author-verified.yml index 72b56f59110..a066c194d99 100644 --- a/.github/workflows/author-verified.yml +++ b/.github/workflows/author-verified.yml @@ -16,7 +16,7 @@ jobs: if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'author-verification-requested') uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" ref: v40 path: ./actions - name: Install Actions diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d509cce2a33..08775eab933 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -123,22 +123,22 @@ jobs: CHILD_CONCURRENCY: "1" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v1 - # TODO: rename azure-pipelines/linux/xvfb.init to github-actions - - run: | - sudo apt-get update - sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 - sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb - sudo chmod +x /etc/init.d/xvfb - sudo update-rc.d xvfb defaults - sudo service xvfb start - name: Setup Build Environment - - uses: actions/setup-node@v1 - with: - node-version: 10 - - run: yarn --frozen-lockfile - name: Install Dependencies - - run: yarn monaco-compile-check - name: Run Monaco Editor Checks - - run: yarn gulp editor-esm-bundle - name: Editor Distro & ESM Bundle + - uses: actions/checkout@v1 + # TODO: rename azure-pipelines/linux/xvfb.init to github-actions + - run: | + sudo apt-get update + sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 + sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb + sudo chmod +x /etc/init.d/xvfb + sudo update-rc.d xvfb defaults + sudo service xvfb start + name: Setup Build Environment + - uses: actions/setup-node@v1 + with: + node-version: 10 + - run: yarn --frozen-lockfile + name: Install Dependencies + - run: yarn monaco-compile-check + name: Run Monaco Editor Checks + - run: yarn gulp editor-esm-bundle + name: Editor Distro & ESM Bundle diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 017708844a4..88761f8aa9a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,48 +2,47 @@ name: "Code Scanning" on: schedule: - - cron: '0 0 * * 2' + - cron: "0 0 * * 2" jobs: CodeQL-Build: - # CodeQL runs on ubuntu-latest and windows-latest runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: javascript + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: javascript - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml index 37b6f626fe2..bda1b25092d 100644 --- a/.github/workflows/commands.yml +++ b/.github/workflows/commands.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" path: ./actions ref: v40 - name: Install Actions diff --git a/.github/workflows/deep-classifier-monitor.yml b/.github/workflows/deep-classifier-monitor.yml index eff700780cc..439d2f2a46b 100644 --- a/.github/workflows/deep-classifier-monitor.yml +++ b/.github/workflows/deep-classifier-monitor.yml @@ -10,7 +10,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" ref: v40 path: ./actions - name: Install Actions diff --git a/.github/workflows/deep-classifier-runner.yml b/.github/workflows/deep-classifier-runner.yml index 541e756f068..ffa11badc9c 100644 --- a/.github/workflows/deep-classifier-runner.yml +++ b/.github/workflows/deep-classifier-runner.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" ref: v40 path: ./actions - name: Install Actions diff --git a/.github/workflows/deep-classifier-scraper.yml b/.github/workflows/deep-classifier-scraper.yml index 9e8e58b274e..1ce6faed4b2 100644 --- a/.github/workflows/deep-classifier-scraper.yml +++ b/.github/workflows/deep-classifier-scraper.yml @@ -10,7 +10,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" ref: v40 path: ./actions - name: Install Actions diff --git a/.github/workflows/devcontainer-cache.yml b/.github/workflows/devcontainer-cache.yml index 82290a475ee..a250b56cd7a 100644 --- a/.github/workflows/devcontainer-cache.yml +++ b/.github/workflows/devcontainer-cache.yml @@ -4,12 +4,12 @@ on: push: # Currently doing this for master, but could be done for PRs as well branches: - - 'master' + - "master" # Only updates to these files result in changes to installed packages, so skip otherwise paths: - - '**/package-lock.json' - - '**/yarn.lock' + - "**/package-lock.json" + - "**/yarn.lock" jobs: devcontainer: @@ -38,4 +38,3 @@ jobs: if [ "$GIT_BRANCH" == "" ]; then GIT_BRANCH=master; fi .devcontainer/cache/build-cache-image.sh "${{ secrets.CONTAINER_IMAGE_REGISTRY }}/public/vscode/devcontainers/repos/microsoft/vscode" "${GIT_BRANCH}" - diff --git a/.github/workflows/english-please.yml b/.github/workflows/english-please.yml index 22ea39a221c..7336c429df1 100644 --- a/.github/workflows/english-please.yml +++ b/.github/workflows/english-please.yml @@ -12,7 +12,7 @@ jobs: if: contains(github.event.issue.labels.*.name, '*english-please') uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" ref: v40 path: ./actions - name: Install Actions diff --git a/.github/workflows/feature-request.yml b/.github/workflows/feature-request.yml index 29e2b734123..4a3c30065f7 100644 --- a/.github/workflows/feature-request.yml +++ b/.github/workflows/feature-request.yml @@ -16,7 +16,7 @@ jobs: if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request') uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" path: ./actions ref: v40 - name: Install Actions diff --git a/.github/workflows/latest-release-monitor.yml b/.github/workflows/latest-release-monitor.yml index 8b246ec01d2..190da52ba32 100644 --- a/.github/workflows/latest-release-monitor.yml +++ b/.github/workflows/latest-release-monitor.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" path: ./actions ref: v40 - name: Install Actions diff --git a/.github/workflows/locker.yml b/.github/workflows/locker.yml index 9f3a32b7be3..abfce92748b 100644 --- a/.github/workflows/locker.yml +++ b/.github/workflows/locker.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" path: ./actions ref: v40 - name: Install Actions diff --git a/.github/workflows/needs-more-info-closer.yml b/.github/workflows/needs-more-info-closer.yml index 6f3d68cd0b8..3475b3ae878 100644 --- a/.github/workflows/needs-more-info-closer.yml +++ b/.github/workflows/needs-more-info-closer.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" path: ./actions ref: v40 - name: Install Actions @@ -24,7 +24,7 @@ jobs: token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} label: needs more info closeDays: 7 - additionalTeam: "cleidigh|usernamehw|gjsjohnmurray|IllusionMH" + 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: 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 b678a00ba00..f06ba0f4ea0 100644 --- a/.github/workflows/on-label.yml +++ b/.github/workflows/on-label.yml @@ -10,7 +10,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" ref: v40 path: ./actions - name: Install Actions diff --git a/.github/workflows/on-open.yml b/.github/workflows/on-open.yml index dfdee7c7f86..9e9076c11fa 100644 --- a/.github/workflows/on-open.yml +++ b/.github/workflows/on-open.yml @@ -10,7 +10,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" ref: v40 path: ./actions - name: Install Actions diff --git a/.github/workflows/release-pipeline-labeler.yml b/.github/workflows/release-pipeline-labeler.yml index a9c0bb26e5c..b4a4f355fb5 100644 --- a/.github/workflows/release-pipeline-labeler.yml +++ b/.github/workflows/release-pipeline-labeler.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout Actions uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" ref: v40 path: ./actions - name: Checkout Repo diff --git a/.github/workflows/rich-navigation.yml b/.github/workflows/rich-navigation.yml index 0f00e8071d6..aee0796fa28 100644 --- a/.github/workflows/rich-navigation.yml +++ b/.github/workflows/rich-navigation.yml @@ -9,28 +9,28 @@ jobs: richnav: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2 - - uses: actions/cache@v2 - id: caching-stage - name: Cache VS Code dependencies - with: - path: node_modules - key: ${{ runner.os }}-dependencies-${{ hashfiles('yarn.lock') }} - restore-keys: ${{ runner.os }}-dependencies- + - uses: actions/cache@v2 + id: caching-stage + name: Cache VS Code dependencies + with: + path: node_modules + key: ${{ runner.os }}-dependencies-${{ hashfiles('yarn.lock') }} + restore-keys: ${{ runner.os }}-dependencies- - - uses: actions/setup-node@v1 - with: - node-version: 10 + - uses: actions/setup-node@v1 + with: + node-version: 10 - - name: Install dependencies - if: steps.caching-stage.outputs.cache-hit != 'true' - run: yarn --frozen-lockfile - env: - CHILD_CONCURRENCY: 1 + - name: Install dependencies + if: steps.caching-stage.outputs.cache-hit != 'true' + run: yarn --frozen-lockfile + env: + CHILD_CONCURRENCY: 1 - - uses: microsoft/RichCodeNavIndexer@v0.1 - with: - languages: typescript - repo-token: ${{ secrets.GITHUB_TOKEN }} - continue-on-error: true + - uses: microsoft/RichCodeNavIndexer@v0.1 + with: + languages: typescript + repo-token: ${{ secrets.GITHUB_TOKEN }} + continue-on-error: true diff --git a/.github/workflows/test-plan-item-validator.yml b/.github/workflows/test-plan-item-validator.yml index 0c26549d1d8..57fcaa53165 100644 --- a/.github/workflows/test-plan-item-validator.yml +++ b/.github/workflows/test-plan-item-validator.yml @@ -12,7 +12,7 @@ jobs: if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item') uses: actions/checkout@v2 with: - repository: 'microsoft/vscode-github-triage-actions' + repository: "microsoft/vscode-github-triage-actions" path: ./actions ref: v40 - name: Install Actions diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index 0d6e4533429..605197ab069 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -2,43 +2,37 @@ { "kind": 1, "language": "markdown", - "value": "# Endgame", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "## Macros", + "value": "#### Macros", "editable": true }, { "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\n\n$MILESTONE=milestone:\"October 2020\"\n\n$MINE=assignee:@me", + "value": "$REPOS=repo:microsoft/vscode \n\t repo:microsoft/vscode-internalbacklog\n\t repo:microsoft/vscode-js-debug\n\t repo:microsoft/vscode-remote-release\n\t repo:microsoft/vscode-pull-request-github\n\t repo:microsoft/vscode-settings-sync-server\n\n$MILESTONE=milestone:\"November 2020\"", + "editable": false + }, + { + "kind": 1, + "language": "markdown", + "value": "# Preparation", "editable": true }, { "kind": 1, "language": "markdown", - "value": "## Endgame Champion", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "### Test Plan Items", + "value": "## Open Issues on the Milestone", "editable": true }, { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE label:testplan-item is:open", + "value": "$REPOS $MILESTONE is:issue is:open", "editable": true }, { "kind": 1, "language": "markdown", - "value": "### Feature Requests Missing Labels", + "value": "## Feature Requests Missing Labels", "editable": true }, { @@ -50,133 +44,55 @@ { "kind": 1, "language": "markdown", - "value": "### Open Issues on the Milestone", + "value": "# Testing", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Test Plan Items", "editable": true }, { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -label:testplan-item -label:iteration-plan -label:endgame-plan is:open", + "value": "$REPOS $MILESTONE is:issue is:open label:testplan-item", "editable": true }, { "kind": 1, "language": "markdown", - "value": "## Testing", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "### My Assigned Test Plan Items", + "value": "## Verification Needed", "editable": true }, { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE $MINE label:testplan-item is:open", + "value": "$REPOS $MILESTONE is:issue is:closed label:feature-request label:verification-needed", "editable": true }, { "kind": 1, "language": "markdown", - "value": "### My Created Test Plan Items", + "value": "# Verification", "editable": true }, { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE author:@me label:testplan-item", + "value": "$REPOS $MILESTONE is:issue is:closed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found", "editable": true }, { "kind": 1, "language": "markdown", - "value": "## Verification", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "### Issues to Verify", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "#### Issues filed by me", + "value": "# Candidates", "editable": true }, { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE author:@me sort:updated-asc is:closed is:issue label:bug -label:verified -label:on-testplan -label:duplicate -label:*duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "#### Issues filed by others", - "editable": true - }, - { - "kind": 2, - "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE -author:@me sort:updated-asc is:closed is:issue label:bug -label:verified -label:on-testplan -label:duplicate -label:*duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "### Verification Needed", - "editable": true - }, - { - "kind": 2, - "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate ", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "### My Issues Needing Verification", - "editable": true - }, - { - "kind": 2, - "language": "github-issues", - "value": "$REPOS $MILESTONE $MINE sort:updated-desc is:closed is:issue -label:verified -label:on-testplan -label:duplicate -label:*duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found\n", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "### My Open Issues", - "editable": true - }, - { - "kind": 2, - "language": "github-issues", - "value": "$REPOS $MILESTONE $MINE is:open is:issue", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "## Documentation", - "editable": true - }, - { - "kind": 1, - "language": "markdown", - "value": "### Needing Release Notes", - "editable": true - }, - { - "kind": 2, - "language": "github-issues", - "value": "repo:microsoft/vscode $MILESTONE $MINE is:closed label:feature-request -label:on-release-notes", + "value": "$REPOS $MILESTONE label:candidate", "editable": true } ] \ No newline at end of file diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues new file mode 100644 index 00000000000..7793fb88d32 --- /dev/null +++ b/.vscode/notebooks/my-endgame.github-issues @@ -0,0 +1,194 @@ +[ + { + "kind": 1, + "language": "markdown", + "value": "#### Macros", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS=repo:microsoft/vscode \n\t repo:microsoft/vscode-internalbacklog\n\t repo:microsoft/vscode-js-debug\n\t repo:microsoft/vscode-remote-release\n\t repo:microsoft/vscode-pull-request-github\n\t repo:microsoft/vscode-settings-sync-server\n\n$MILESTONE=milestone:\"November 2020\"\n\n$MINE=assignee:@me", + "editable": false + }, + { + "kind": 1, + "language": "markdown", + "value": "# Preparation", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Open Issues on the Milestone", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE $MINE is:issue is:open", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Feature Requests Missing Labels", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE $MINE is:issue is:closed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Test Plan Items", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE is:issue is:open author:@me label:testplan-item", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Verification Needed", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE $MINE is:issue is:closed label:feature-request label:verification-needed", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "# Testing", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Test Plan Items", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE $MINE is:issue is:open label:testplan-item", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Verification Needed", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed -assignee:@me label:feature-request label:verification-needed", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "# Fixing", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Open Issues", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE $MINE is:issue is:open", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Open Bugs", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE $MINE is:issue is:open label:bug", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "# Verification", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## My Issues (verification-steps-needed)", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE $MINE is:issue is:open label:bug label:verification-steps-needed", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## My Issues (verification-found)", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE $MINE is:issue is:open label:bug label:verification-found", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Issues filed by me", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed author:@me sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "## Issues filed by others", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed -author:@me sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found", + "editable": true + }, + { + "kind": 1, + "language": "markdown", + "value": "# Release Notes", + "editable": true + }, + { + "kind": 2, + "language": "github-issues", + "value": "repo:microsoft/vscode $MILESTONE is:issue is:closed label:feature-request -label:on-release-notes", + "editable": true + } +] \ No newline at end of file diff --git a/.yarnrc b/.yarnrc index d97527dab46..55af88729b8 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://electronjs.org/headers" -target "9.3.3" +target "11.0.2" runtime "electron" diff --git a/build/.cachesalt b/build/.cachesalt index 3f2ee542ad5..0afdafd1118 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -2020-10-05T20:24:23.714Z +2020-11-23T17:57:03.428Z diff --git a/build/azure-pipelines/darwin/continuous-build-darwin.yml b/build/azure-pipelines/darwin/continuous-build-darwin.yml index 954e5bca636..75c28106c5e 100644 --- a/build/azure-pipelines/darwin/continuous-build-darwin.yml +++ b/build/azure-pipelines/darwin/continuous-build-darwin.yml @@ -1,79 +1,79 @@ steps: -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'vscode-build-cache' + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: ".yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "vscode-build-cache" -- script: | - CHILD_CONCURRENCY=1 yarn --frozen-lockfile - displayName: Install Dependencies - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - script: | + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install Dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'vscode-build-cache' - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: ".yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "vscode-build-cache" + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- script: | - set -e - yarn postinstall - displayName: Run postinstall scripts - condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + - script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) -- script: | - yarn electron x64 - displayName: Download Electron + - script: | + yarn electron x64 + displayName: Download Electron -- script: | - yarn monaco-compile-check - displayName: Run Monaco Editor Checks + - script: | + yarn monaco-compile-check + displayName: Run Monaco Editor Checks -- script: | - yarn valid-layers-check - displayName: Run Valid Layers Checks + - script: | + yarn valid-layers-check + displayName: Run Valid Layers Checks -- script: | - yarn compile - displayName: Compile Sources + - script: | + yarn compile + displayName: Compile Sources -- script: | - yarn download-builtin-extensions - displayName: Download Built-in Extensions + - script: | + yarn download-builtin-extensions + displayName: Download Built-in Extensions -- script: | - ./scripts/test.sh --tfs "Unit Tests" - displayName: Run Unit Tests (Electron) + - script: | + ./scripts/test.sh --tfs "Unit Tests" + displayName: Run Unit Tests (Electron) -- script: | - yarn test-browser --browser chromium --browser webkit --browser firefox --tfs "Browser Unit Tests" - displayName: Run Unit Tests (Browser) + - script: | + yarn test-browser --browser chromium --browser webkit --browser firefox --tfs "Browser Unit Tests" + displayName: Run Unit Tests (Browser) -- script: | - ./scripts/test-integration.sh --tfs "Integration Tests" - displayName: Run Integration Tests (Electron) + - script: | + ./scripts/test-integration.sh --tfs "Integration Tests" + displayName: Run Integration Tests (Electron) -- task: PublishPipelineArtifact@0 - inputs: - artifactName: crash-dump-macos - targetPath: .build/crashes - displayName: 'Publish Crash Reports' - continueOnError: true - condition: failed() + - task: PublishPipelineArtifact@0 + inputs: + artifactName: crash-dump-macos + targetPath: .build/crashes + displayName: "Publish Crash Reports" + continueOnError: true + condition: failed() -- task: PublishTestResults@2 - displayName: Publish Tests Results - inputs: - testResultsFiles: '*-results.xml' - searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' - condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: "*-results.xml" + searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" + condition: succeededOrFailed() diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 0500f84accc..1afa0d2ca5c 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -1,270 +1,320 @@ steps: -- script: | - mkdir -p .build - echo -n $BUILD_SOURCEVERSION > .build/commit - echo -n $VSCODE_QUALITY > .build/quality - displayName: Prepare cache flag + - script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + echo -n $VSCODE_QUALITY > .build/quality + displayName: Prepare cache flag -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/commit, .build/quality' - targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' - vstsFeed: 'npm-vscode' - platformIndependent: true - alias: 'Compilation' + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: "build/.cachesalt, .build/commit, .build/quality" + targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min" + vstsFeed: "npm-vscode" + platformIndependent: true + alias: "Compilation" -- script: | - set -e - exit 1 - displayName: Check RestoreCache - condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - script: | + set -e + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- script: | - set -e + - script: | + set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling -- script: | - set -e - git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" - git fetch distro - git merge $(node -p "require('./package.json').distro") - displayName: Merge distro + - script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' + - script: | + echo -n $VSCODE_ARCH > .build/arch + displayName: Prepare arch cache flag -- script: | - set -e - CHILD_CONCURRENCY=1 yarn --frozen-lockfile - displayName: Install dependencies - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - script: | + npx https://aka.ms/enablesecurefeed standAlone + displayName: Switch to Terrapin packages -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: ".build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" -- script: | - set -e - yarn postinstall - displayName: Run postinstall scripts - condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + - script: | + set -e + sudo xcode-select -s /Applications/Xcode_12.2.app + displayName: Switch to Xcode 12 + condition: eq(variables['VSCODE_ARCH'], 'arm64') -- script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality + - script: | + set -e + npm install -g node-gyp@7.1.0 + node-gyp --version + displayName: Update node-gyp + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-darwin-min-ci - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-darwin-min-ci - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-web-darwin-min-ci - displayName: Build + - script: | + set -e + export npm_config_arch=$(VSCODE_ARCH) + export npm_config_node_gyp=$(which node-gyp) + export SDKROOT=/Applications/Xcode_12.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk + ls /Applications/Xcode_12.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ + CHILD_CONCURRENCY=1 yarn --frozen-lockfile --verbose + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- script: | - set -e - ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: ".build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- script: | - set -e - 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')) + - script: | + set -e + export npm_config_arch=$(VSCODE_ARCH) + export npm_config_node_gyp=$(which node-gyp) + export SDKROOT=/Applications/Xcode_12.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk + ls /Applications/Xcode_12.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) -- script: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-darwin - APP_NAME="`ls $APP_ROOT | head -n 1`" - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \ - ./scripts/test-integration.sh --build --tfs "Integration Tests" - displayName: Run integration tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + export SDKROOT=/Applications/Xcode_12.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk + ls /Applications/Xcode_12.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ + yarn electron-rebuild + displayName: Rebuild native modules for ARM64 + condition: eq(variables['VSCODE_ARCH'], 'arm64') -- 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 + node build/azure-pipelines/mixin + displayName: Mix in quality -- script: | - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-darwin - APP_NAME="`ls $APP_ROOT | head -n 1`" - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \ - ./resources/server/test/test-remote-integration.sh - displayName: Run remote integration tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-darwin-$(VSCODE_ARCH)-min-ci + displayName: Build -- script: | - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-darwin - APP_NAME="`ls $APP_ROOT | head -n 1`" - yarn smoketest --build "$APP_ROOT/$APP_NAME" - continueOnError: true - displayName: Run smoke tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-darwin-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-web-darwin-min-ci + displayName: Build reh + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) -- script: | - set -e - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \ - yarn smoketest --web --headless - continueOnError: true - displayName: Run smoke tests (Browser) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + yarn electron $(VSCODE_ARCH) + displayName: Download Electron + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- task: PublishPipelineArtifact@0 - inputs: - artifactName: crash-dump-macos - targetPath: .build/crashes - displayName: 'Publish Crash Reports' - continueOnError: true - condition: failed() + - script: | + set -e + security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain + security default-keychain -s $(agent.tempdirectory)/buildagent.keychain + security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain + echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12 + security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain + VSCODE_ARCH="$(VSCODE_ARCH)" DEBUG=electron-osx-sign* node build/darwin/sign.js + displayName: Set Hardened Entitlements -- task: PublishTestResults@2 - displayName: Publish Tests Results - inputs: - testResultsFiles: '*-results.xml' - searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' - condition: succeededOrFailed() + - script: | + set -e + ./scripts/test.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain - security default-keychain -s $(agent.tempdirectory)/buildagent.keychain - security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain - echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12 - security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain - DEBUG=electron-osx-sign* node build/darwin/sign.js - displayName: Set Hardened Entitlements + - script: | + set -e + 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_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - pushd $(agent.builddirectory)/VSCode-darwin && zip -r -X -y $(agent.builddirectory)/VSCode-darwin.zip * && popd - displayName: Archive build + - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \ + ./scripts/test-integration.sh --build --tfs "Integration Tests" + displayName: Run integration tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - inputs: - ConnectedServiceName: 'ESRP CodeSign' - FolderPath: '$(agent.builddirectory)' - Pattern: 'VSCode-darwin.zip' - signConfigType: inlineSignParams - inlineOperation: | - [ - { - "keyCode": "CP-401337-Apple", - "operationSetCode": "MacAppDeveloperSign", - "parameters": [ - { - "parameterName": "Hardening", - "parameterValue": "--options=runtime" - } - ], - "toolName": "sign", - "toolVersion": "1.0" - } - ] - SessionTimeout: 60 - displayName: Codesign + - 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_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - zip -d $(agent.builddirectory)/VSCode-darwin.zip "*.pkg" - displayName: Clean Archive + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \ + ./resources/server/test/test-remote-integration.sh + displayName: Run remote integration tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - APP_ROOT=$(agent.builddirectory)/VSCode-darwin - APP_NAME="`ls $APP_ROOT | head -n 1`" - BUNDLE_IDENTIFIER=$(node -p "require(\"$APP_ROOT/$APP_NAME/Contents/Resources/app/product.json\").darwinBundleIdentifier") - echo "##vso[task.setvariable variable=BundleIdentifier]$BUNDLE_IDENTIFIER" - displayName: Export bundle identifier + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + yarn smoketest --build "$APP_ROOT/$APP_NAME" + continueOnError: true + displayName: Run smoke tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - inputs: - ConnectedServiceName: 'ESRP CodeSign' - FolderPath: '$(agent.builddirectory)' - Pattern: 'VSCode-darwin.zip' - signConfigType: inlineSignParams - inlineOperation: | - [ - { - "keyCode": "CP-401337-Apple", - "operationSetCode": "MacAppNotarize", - "parameters": [ - { - "parameterName": "BundleId", - "parameterValue": "$(BundleIdentifier)" - } - ], - "toolName": "sign", - "toolVersion": "1.0" - } - ] - SessionTimeout: 60 - displayName: Notarization + - script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \ + yarn smoketest --web --headless + continueOnError: true + displayName: Run smoke tests (Browser) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-darwin - APP_NAME="`ls $APP_ROOT | head -n 1`" - "$APP_ROOT/$APP_NAME/Contents/Resources/app/bin/code" --export-default-configuration=.build - displayName: Verify start after signing (export configuration) + - task: PublishPipelineArtifact@0 + inputs: + artifactName: crash-dump-macos-$(VSCODE_ARCH) + targetPath: .build/crashes + displayName: "Publish Crash Reports" + continueOnError: true + condition: failed() -- script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_ARCH="$(VSCODE_ARCH)" \ - ./build/azure-pipelines/darwin/publish.sh - displayName: Publish + - task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: "*-results.xml" + searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" + condition: succeededOrFailed() -- script: | - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ - yarn gulp upload-vscode-configuration - displayName: Upload configuration (for Bing settings search) - continueOnError: true + - script: | + set -e + pushd $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) && zip -r -X -y $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip * && popd + displayName: Archive build -- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - continueOnError: true + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + inputs: + ConnectedServiceName: "ESRP CodeSign" + FolderPath: "$(agent.builddirectory)" + Pattern: "VSCode-darwin-$(VSCODE_ARCH).zip" + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-401337-Apple", + "operationSetCode": "MacAppDeveloperSign", + "parameters": [ + { + "parameterName": "Hardening", + "parameterValue": "--options=runtime" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 60 + displayName: Codesign + + - script: | + zip -d $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip "*.pkg" + displayName: Clean Archive + + - script: | + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + BUNDLE_IDENTIFIER=$(node -p "require(\"$APP_ROOT/$APP_NAME/Contents/Resources/app/product.json\").darwinBundleIdentifier") + echo "##vso[task.setvariable variable=BundleIdentifier]$BUNDLE_IDENTIFIER" + displayName: Export bundle identifier + + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + inputs: + ConnectedServiceName: "ESRP CodeSign" + FolderPath: "$(agent.builddirectory)" + Pattern: "VSCode-darwin-$(VSCODE_ARCH).zip" + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-401337-Apple", + "operationSetCode": "MacAppNotarize", + "parameters": [ + { + "parameterName": "BundleId", + "parameterValue": "$(BundleIdentifier)" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 60 + displayName: Notarization + + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + "$APP_ROOT/$APP_NAME/Contents/Resources/app/bin/code" --export-default-configuration=.build + displayName: Verify start after signing (export configuration) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + VSCODE_ARCH="$(VSCODE_ARCH)" \ + ./build/azure-pipelines/darwin/publish.sh + displayName: Publish + + - script: | + AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ + yarn gulp upload-vscode-configuration + displayName: Upload configuration (for Bing settings search) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + continueOnError: true + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: "Component Detection" + continueOnError: true diff --git a/build/azure-pipelines/darwin/publish.sh b/build/azure-pipelines/darwin/publish.sh index 51ac2e6355d..c9f5b4bab53 100755 --- a/build/azure-pipelines/darwin/publish.sh +++ b/build/azure-pipelines/darwin/publish.sh @@ -1,12 +1,18 @@ #!/usr/bin/env bash set -e +# Publish DEB +case $VSCODE_ARCH in + x64) ASSET_ID="darwin" ;; + arm64) ASSET_ID="darwin-arm64" ;; +esac + # publish the build node build/azure-pipelines/common/createAsset.js \ - darwin \ + "$ASSET_ID" \ archive \ - "VSCode-darwin-$VSCODE_QUALITY.zip" \ - ../VSCode-darwin.zip + "VSCode-$ASSET_ID.zip" \ + ../VSCode-darwin-$VSCODE_ARCH.zip if [ "$VSCODE_ARCH" == "x64" ]; then # package Remote Extension Host diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index f9bdf7fef8e..331fbf9675e 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -1,42 +1,42 @@ trigger: branches: - include: ['master', 'release/*'] + include: ["master", "release/*"] pr: branches: - include: ['master', 'release/*'] + include: ["master", "release/*"] steps: -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- script: | - set -e + - script: | + set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" - git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git" - git fetch distro + git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git" + git fetch distro - # Push master branch into oss/master - git push distro origin/master:refs/heads/oss/master + # Push master branch into oss/master + git push distro origin/master:refs/heads/oss/master - # Push every release branch into oss/release - git for-each-ref --format="%(refname:short)" refs/remotes/origin/release/* | sed 's/^origin\/\(.*\)$/\0:refs\/heads\/oss\/\1/' | xargs git push distro + # Push every release branch into oss/release + git for-each-ref --format="%(refname:short)" refs/remotes/origin/release/* | sed 's/^origin\/\(.*\)$/\0:refs\/heads\/oss\/\1/' | xargs git push distro - git merge $(node -p "require('./package.json').distro") + git merge $(node -p "require('./package.json').distro") - displayName: Sync & Merge Distro + displayName: Sync & Merge Distro diff --git a/build/azure-pipelines/exploration-build.yml b/build/azure-pipelines/exploration-build.yml index cf1ced09dc8..d4788edfd1d 100644 --- a/build/azure-pipelines/exploration-build.yml +++ b/build/azure-pipelines/exploration-build.yml @@ -1,40 +1,40 @@ pool: - vmImage: 'Ubuntu-16.04' + vmImage: "Ubuntu-16.04" trigger: branches: - include: ['master'] + include: ["master"] pr: branches: - include: ['master'] + include: ["master"] steps: -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- script: | - set -e + - script: | + set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" - git checkout origin/electron-11.x.y - git merge origin/master + git checkout origin/electron-11.x.y + git merge origin/master - # Push master branch into exploration branch - git push origin HEAD:electron-11.x.y + # Push master branch into exploration branch + git push origin HEAD:electron-11.x.y - displayName: Sync & Merge Exploration + displayName: Sync & Merge Exploration diff --git a/build/azure-pipelines/linux/continuous-build-linux.yml b/build/azure-pipelines/linux/continuous-build-linux.yml index 58e14ab0dcd..44cb9829472 100644 --- a/build/azure-pipelines/linux/continuous-build-linux.yml +++ b/build/azure-pipelines/linux/continuous-build-linux.yml @@ -1,92 +1,92 @@ steps: -- script: | - set -e - sudo apt-get update - sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 - sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb - sudo chmod +x /etc/init.d/xvfb - sudo update-rc.d xvfb defaults - sudo service xvfb start + - script: | + set -e + sudo apt-get update + sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 + sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb + sudo chmod +x /etc/init.d/xvfb + sudo update-rc.d xvfb defaults + sudo service xvfb start -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'vscode-build-cache' + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: ".yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "vscode-build-cache" -- script: | - CHILD_CONCURRENCY=1 yarn --frozen-lockfile - displayName: Install Dependencies - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - script: | + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install Dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'vscode-build-cache' - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: ".yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "vscode-build-cache" + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- script: | - set -e - yarn postinstall - displayName: Run postinstall scripts - condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + - script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) -- script: | - yarn electron x64 - displayName: Download Electron + - script: | + yarn electron x64 + displayName: Download Electron -- script: | - yarn gulp hygiene - displayName: Run Hygiene Checks + - script: | + yarn gulp hygiene + displayName: Run Hygiene Checks -- script: | - yarn monaco-compile-check - displayName: Run Monaco Editor Checks + - script: | + yarn monaco-compile-check + displayName: Run Monaco Editor Checks -- script: | - yarn valid-layers-check - displayName: Run Valid Layers Checks + - script: | + yarn valid-layers-check + displayName: Run Valid Layers Checks -- script: | - yarn compile - displayName: Compile Sources + - script: | + yarn compile + displayName: Compile Sources -- script: | - yarn download-builtin-extensions - displayName: Download Built-in Extensions + - script: | + yarn download-builtin-extensions + displayName: Download Built-in Extensions -- script: | - DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests" - displayName: Run Unit Tests (Electron) + - script: | + DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests" + displayName: Run Unit Tests (Electron) -- script: | - DISPLAY=:10 yarn test-browser --browser chromium --tfs "Browser Unit Tests" - displayName: Run Unit Tests (Browser) + - script: | + DISPLAY=:10 yarn test-browser --browser chromium --tfs "Browser Unit Tests" + displayName: Run Unit Tests (Browser) -- script: | - DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" - displayName: Run Integration Tests (Electron) + - script: | + DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" + displayName: Run Integration Tests (Electron) -- task: PublishPipelineArtifact@0 - inputs: - artifactName: crash-dump-linux - targetPath: .build/crashes - displayName: 'Publish Crash Reports' - continueOnError: true - condition: failed() + - task: PublishPipelineArtifact@0 + inputs: + artifactName: crash-dump-linux + targetPath: .build/crashes + displayName: "Publish Crash Reports" + continueOnError: true + condition: failed() -- task: PublishTestResults@2 - displayName: Publish Tests Results - inputs: - testResultsFiles: '*-results.xml' - searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' - condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: "*-results.xml" + searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" + condition: succeededOrFailed() diff --git a/build/azure-pipelines/linux/product-build-alpine.yml b/build/azure-pipelines/linux/product-build-alpine.yml index d58a2de2907..ce4a620f843 100644 --- a/build/azure-pipelines/linux/product-build-alpine.yml +++ b/build/azure-pipelines/linux/product-build-alpine.yml @@ -21,7 +21,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.18.3" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 031a491648a..1baa784b50e 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -1,217 +1,215 @@ steps: -- script: | - mkdir -p .build - echo -n $BUILD_SOURCEVERSION > .build/commit - echo -n $VSCODE_QUALITY > .build/quality - displayName: Prepare cache flag + - script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + echo -n $VSCODE_QUALITY > .build/quality + displayName: Prepare cache flag -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/commit, .build/quality' - targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' - vstsFeed: 'npm-vscode' - platformIndependent: true - alias: 'Compilation' + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: "build/.cachesalt, .build/commit, .build/quality" + targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min" + vstsFeed: "npm-vscode" + platformIndependent: true + alias: "Compilation" -- script: | - set -e - exit 1 - displayName: Check RestoreCache - condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - script: | + set -e + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling -- script: | - set -e - git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" - git fetch distro - git merge $(node -p "require('./package.json').distro") - displayName: Merge distro + - script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro -- script: | - echo -n $VSCODE_ARCH > .build/arch - displayName: Prepare arch cache flag + - script: | + npx https://aka.ms/enablesecurefeed standAlone + displayName: Switch to Terrapin packages -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: '.build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' + - script: | + echo -n $VSCODE_ARCH > .build/arch + displayName: Prepare arch cache flag -- script: | - set -e - CHILD_CONCURRENCY=1 npm_config_arch=$(NPM_ARCH) yarn --frozen-lockfile - displayName: Install dependencies - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: ".build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: '.build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - script: | + set -e + CHILD_CONCURRENCY=1 npm_config_arch=$(NPM_ARCH) yarn --frozen-lockfile + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- script: | - set -e - yarn postinstall - displayName: Run postinstall scripts - condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: ".build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality + - script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) -- script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-linux-$(VSCODE_ARCH)-min-ci - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-linux-$(VSCODE_ARCH)-min-ci - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-web-linux-$(VSCODE_ARCH)-min-ci - displayName: Build + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality -- script: | - set -e - service xvfb start - displayName: Start xvfb - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-linux-$(VSCODE_ARCH)-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-linux-$(VSCODE_ARCH)-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-web-linux-$(VSCODE_ARCH)-min-ci + displayName: Build -- script: | - set -e - DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - DISPLAY=:10 yarn test-browser --build --browser chromium --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + DISPLAY=:10 yarn test-browser --build --browser chromium --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ - DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests" - displayName: Run integration tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ + DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests" + displayName: Run integration tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \ - DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium - displayName: Run integration tests (Browser) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \ + DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium + displayName: Run integration tests (Browser) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ - VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ - DISPLAY=:10 ./resources/server/test/test-remote-integration.sh - displayName: Run remote integration tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ + DISPLAY=:10 ./resources/server/test/test-remote-integration.sh + displayName: Run remote integration tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- task: PublishPipelineArtifact@0 - inputs: - artifactName: 'crash-dump-linux-$(VSCODE_ARCH)' - targetPath: .build/crashes - displayName: 'Publish Crash Reports' - continueOnError: true - condition: failed() + - task: PublishPipelineArtifact@0 + inputs: + artifactName: "crash-dump-linux-$(VSCODE_ARCH)" + targetPath: .build/crashes + displayName: "Publish Crash Reports" + continueOnError: true + condition: failed() -- task: PublishTestResults@2 - displayName: Publish Tests Results - inputs: - testResultsFiles: '*-results.xml' - searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' - condition: and(succeededOrFailed(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: "*-results.xml" + searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" + condition: and(succeededOrFailed(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-deb" - yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-rpm" - displayName: Build deb, rpm packages + - script: | + set -e + yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-deb" + yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-rpm" + displayName: Build deb, rpm packages -- script: | - set -e - yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-snap" - displayName: Prepare snap package - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + - script: | + set -e + yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-snap" + displayName: Prepare snap package + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) -# needed for code signing -- task: UseDotNet@2 - displayName: 'Install .NET Core SDK 2.x' - inputs: - version: 2.x + # needed for code signing + - task: UseDotNet@2 + displayName: "Install .NET Core SDK 2.x" + inputs: + version: 2.x -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - inputs: - ConnectedServiceName: 'ESRP CodeSign' - FolderPath: '.build/linux/rpm' - Pattern: '*.rpm' - signConfigType: inlineSignParams - inlineOperation: | - [ - { - "keyCode": "CP-450779-Pgp", - "operationSetCode": "LinuxSign", - "parameters": [ ], - "toolName": "sign", - "toolVersion": "1.0" - } - ] - SessionTimeout: 120 - displayName: Codesign rpm + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + inputs: + ConnectedServiceName: "ESRP CodeSign" + FolderPath: ".build/linux/rpm" + Pattern: "*.rpm" + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-450779-Pgp", + "operationSetCode": "LinuxSign", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 120 + displayName: Codesign rpm -- script: | - set -e - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - VSCODE_ARCH="$(VSCODE_ARCH)" \ - ./build/azure-pipelines/linux/publish.sh - displayName: Publish + - script: | + set -e + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + VSCODE_ARCH="$(VSCODE_ARCH)" \ + ./build/azure-pipelines/linux/publish.sh + displayName: Publish -- task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline Artifact' - inputs: - artifactName: 'snap-$(VSCODE_ARCH)' - targetPath: .build/linux/snap-tarball - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + - task: PublishPipelineArtifact@0 + displayName: "Publish Pipeline Artifact" + inputs: + artifactName: "snap-$(VSCODE_ARCH)" + targetPath: .build/linux/snap-tarball + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) -- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - continueOnError: true + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: "Component Detection" + continueOnError: true diff --git a/build/azure-pipelines/linux/snap-build-linux.yml b/build/azure-pipelines/linux/snap-build-linux.yml index 9084a9f6093..1cd7eb70c64 100644 --- a/build/azure-pipelines/linux/snap-build-linux.yml +++ b/build/azure-pipelines/linux/snap-build-linux.yml @@ -1,7 +1,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.18.3" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 1c45de07f3e..57c0fac5d4e 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -2,162 +2,180 @@ trigger: none pr: none schedules: -- cron: "0 5 * * Mon-Fri" - displayName: Mon-Fri at 7:00 - branches: - include: - - master + - cron: "0 5 * * Mon-Fri" + displayName: Mon-Fri at 7:00 + branches: + include: + - master resources: containers: - - container: vscode-x64 - image: vscodehub.azurecr.io/vscode-linux-build-agent:x64 - endpoint: VSCodeHub - - container: vscode-arm64 - image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-arm64 - endpoint: VSCodeHub - - container: vscode-armhf - image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-armhf - endpoint: VSCodeHub - - container: snapcraft - image: snapcore/snapcraft:stable + - container: vscode-x64 + image: vscodehub.azurecr.io/vscode-linux-build-agent:bionic + endpoint: VSCodeHub + options: --user 0:0 + - container: vscode-arm64 + image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-arm64 + endpoint: VSCodeHub + - container: vscode-armhf + image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-armhf + 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: Compile + jobs: + - job: Compile + pool: + vmImage: "Ubuntu-18.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')) - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: win32/product-build-win32.yml - - - job: Windows32 - condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true')) - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: ia32 - steps: - - template: win32/product-build-win32.yml - - - job: WindowsARM64 - condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32_ARM64'], 'true')) - timeoutInMinutes: 90 - 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 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - steps: - - template: linux/product-build-linux.yml - - - job: LinuxSnap + - stage: Windows dependsOn: - - Linux - condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX'], 'true')) - container: snapcraft - variables: - VSCODE_ARCH: x64 - steps: - - template: linux/snap-build-linux.yml + - 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')) + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: x64 + steps: + - template: win32/product-build-win32.yml - - job: LinuxArmhf - condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true')) - container: vscode-armhf - variables: - VSCODE_ARCH: armhf - NPM_ARCH: armv7l - steps: - - template: linux/product-build-linux.yml + - job: Windows32 + condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true')) + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: ia32 + steps: + - template: win32/product-build-win32.yml - - job: LinuxArm64 - condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ARM64'], 'true')) - container: vscode-arm64 - variables: - VSCODE_ARCH: arm64 - NPM_ARCH: arm64 - steps: - - template: linux/product-build-linux.yml + - job: WindowsARM64 + condition: and(succeeded(), eq(variables['VSCODE_BUILD_WIN32_ARM64'], 'true')) + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: arm64 + steps: + - template: win32/product-build-win32-arm64.yml - - job: LinuxAlpine - condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true')) - steps: - - template: linux/product-build-alpine.yml + - stage: Linux + dependsOn: + - Compile + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) + pool: + vmImage: "Ubuntu-18.04" + jobs: + - job: Linux + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX'], 'true')) + container: vscode-x64 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + steps: + - template: linux/product-build-linux.yml - - job: LinuxWeb - condition: and(succeeded(), eq(variables['VSCODE_BUILD_WEB'], 'true')) - variables: - VSCODE_ARCH: x64 - steps: - - template: web/product-build-web.yml + - job: LinuxSnap + dependsOn: + - Linux + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX'], 'true')) + container: snapcraft + variables: + VSCODE_ARCH: x64 + steps: + - template: linux/snap-build-linux.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')) - timeoutInMinutes: 90 - variables: - VSCODE_ARCH: x64 - steps: - - template: darwin/product-build-darwin.yml + - job: LinuxArmhf + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true')) + container: vscode-armhf + variables: + VSCODE_ARCH: armhf + NPM_ARCH: armv7l + steps: + - template: linux/product-build-linux.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 + - job: LinuxArm64 + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ARM64'], 'true')) + container: vscode-arm64 + variables: + VSCODE_ARCH: arm64 + NPM_ARCH: arm64 + steps: + - template: linux/product-build-linux.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 + - job: LinuxAlpine + condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true')) + steps: + - template: linux/product-build-alpine.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')) + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: x64 + steps: + - template: darwin/product-build-darwin.yml + + - stage: macOSARM64 + dependsOn: + - Compile + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) + pool: + vmImage: macOS-latest + jobs: + - job: macOSARM64 + condition: and(succeeded(), eq(variables['VSCODE_BUILD_MACOS_ARM64'], 'true')) + timeoutInMinutes: 90 + variables: + VSCODE_ARCH: arm64 + steps: + - template: darwin/product-build-darwin.yml + + - stage: Mooncake + dependsOn: + - Windows + - Linux + - macOS + - macOSARM64 + condition: and(succeededOrFailed(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) + pool: + vmImage: "Ubuntu-18.04" + jobs: + - job: SyncMooncake + displayName: Sync Mooncake + steps: + - template: sync-mooncake.yml + + - stage: Publish + dependsOn: + - Windows + - Linux + - macOS + - macOSARM64 + 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-18.04" + jobs: + - job: BuildService + displayName: Build Service + steps: + - template: release.yml diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 3af607a5aae..5ea3587a31f 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -1,147 +1,152 @@ steps: -- script: | - mkdir -p .build - echo -n $BUILD_SOURCEVERSION > .build/commit - echo -n $VSCODE_QUALITY > .build/quality - displayName: Prepare cache flag + - script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + echo -n $VSCODE_QUALITY > .build/quality + displayName: Prepare cache flag -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/commit, .build/quality' - targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' - vstsFeed: 'npm-vscode' - platformIndependent: true - alias: 'Compilation' - dryRun: true + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: "build/.cachesalt, .build/commit, .build/quality" + targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min" + vstsFeed: "npm-vscode" + platformIndependent: true + alias: "Compilation" + dryRun: true -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- script: | - set -e - git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" - git fetch distro - git merge $(node -p "require('./package.json').distro") - displayName: Merge distro - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- script: | - echo -n $VSCODE_ARCH > .build/arch - displayName: Prepare arch cache flag - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + npx https://aka.ms/enablesecurefeed standAlone + displayName: Switch to Terrapin packages + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: '.build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + echo -n $VSCODE_ARCH > .build/arch + displayName: Prepare arch cache flag + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- script: | - set -e - CHILD_CONCURRENCY=1 yarn --frozen-lockfile - displayName: Install dependencies - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: ".build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: '.build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true')) + - script: | + set -e + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true')) -- script: | - set -e - yarn postinstall - displayName: Run postinstall scripts - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: ".build/arch, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true')) -# Mixin must run before optimize, because the CSS loader will -# inline small SVGs -- script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['CacheRestored'], 'true')) -- script: | - set -e - yarn gulp hygiene - yarn monaco-compile-check - yarn valid-layers-check - displayName: Run hygiene, monaco compile & valid layers checks - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + # Mixin must run before optimize, because the CSS loader will + # inline small SVGs + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- script: | - set - - ./build/azure-pipelines/common/extract-telemetry.sh - displayName: Extract Telemetry - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + set -e + yarn gulp hygiene + yarn monaco-compile-check + yarn valid-layers-check + displayName: Run hygiene, monaco compile & valid layers checks + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - AZURE_WEBVIEW_STORAGE_ACCESS_KEY="$(vscode-webview-storage-key)" \ - ./build/azure-pipelines/common/publish-webview.sh - displayName: Publish Webview - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + set - + ./build/azure-pipelines/common/extract-telemetry.sh + displayName: Extract Telemetry + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- script: | - set -e - yarn gulp compile-build - yarn gulp compile-extensions-build - yarn gulp minify-vscode - yarn gulp minify-vscode-reh - yarn gulp minify-vscode-reh-web - displayName: Compile - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + set -e + AZURE_WEBVIEW_STORAGE_ACCESS_KEY="$(vscode-webview-storage-key)" \ + ./build/azure-pipelines/common/publish-webview.sh + displayName: Publish Webview + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- script: | - set -e - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ - node build/azure-pipelines/upload-sourcemaps - displayName: Upload sourcemaps - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + set -e + yarn gulp compile-build + yarn gulp compile-extensions-build + yarn gulp minify-vscode + yarn gulp minify-vscode-reh + yarn gulp minify-vscode-reh-web + displayName: Compile + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- script: | - set -e - VERSION=`node -p "require(\"./package.json\").version"` - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - node build/azure-pipelines/common/createBuild.js $VERSION - displayName: Create build - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + set -e + AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ + node build/azure-pipelines/upload-sourcemaps + displayName: Upload sourcemaps + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/commit, .build/quality' - targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' - vstsFeed: 'npm-vscode' - platformIndependent: true - alias: 'Compilation' - condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + - script: | + set -e + VERSION=`node -p "require(\"./package.json\").version"` + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + node build/azure-pipelines/common/createBuild.js $VERSION + displayName: Create build + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) + + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: "build/.cachesalt, .build/commit, .build/quality" + targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min" + vstsFeed: "npm-vscode" + platformIndependent: true + alias: "Compilation" + condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) diff --git a/build/azure-pipelines/publish-types/publish-types.yml b/build/azure-pipelines/publish-types/publish-types.yml index 10b6aa4e16a..0e3f4e4daa4 100644 --- a/build/azure-pipelines/publish-types/publish-types.yml +++ b/build/azure-pipelines/publish-types/publish-types.yml @@ -2,82 +2,82 @@ trigger: branches: - include: ['refs/tags/*'] + include: ["refs/tags/*"] pr: none steps: -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- bash: | - TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) - CHANNEL="G1C14HJ2F" + - bash: | + TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) + CHANNEL="G1C14HJ2F" - if [ "$TAG_VERSION" == "1.999.0" ]; then - MESSAGE=". Someone pushed 1.999.0 tag. Please delete it ASAP from remote and local." + if [ "$TAG_VERSION" == "1.999.0" ]; then + MESSAGE=". Someone pushed 1.999.0 tag. Please delete it ASAP from remote and local." + + curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ + -H 'Content-type: application/json; charset=utf-8' \ + --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE"'"}' \ + https://slack.com/api/chat.postMessage + + exit 1 + fi + displayName: Check 1.999.0 tag + + - bash: | + # Install build dependencies + (cd build && yarn) + node build/azure-pipelines/publish-types/check-version.js + displayName: Check version + + - bash: | + git config --global user.email "vscode@microsoft.com" + git config --global user.name "VSCode" + + git clone https://$(GITHUB_TOKEN)@github.com/DefinitelyTyped/DefinitelyTyped.git --depth=1 + node build/azure-pipelines/publish-types/update-types.js + + TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) + + cd DefinitelyTyped + + git diff --color | cat + git add -A + git status + git checkout -b "vscode-types-$TAG_VERSION" + git commit -m "VS Code $TAG_VERSION Extension API" + git push origin "vscode-types-$TAG_VERSION" + + displayName: Push update to DefinitelyTyped + + - bash: | + TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) + CHANNEL="G1C14HJ2F" + + MESSAGE="DefinitelyTyped/DefinitelyTyped#vscode-types-$TAG_VERSION created. Endgame master, please open this link, examine changes and create a PR:" + LINK="https://github.com/DefinitelyTyped/DefinitelyTyped/compare/vscode-types-$TAG_VERSION?quick_pull=1&body=Updating%20VS%20Code%20Extension%20API.%20See%20https%3A%2F%2Fgithub.com%2Fmicrosoft%2Fvscode%2Fissues%2F70175%20for%20details." + MESSAGE2="[@eamodio, @jrieken, @kmaetzel, @egamma]. Please review and merge PR to publish @types/vscode." curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ -H 'Content-type: application/json; charset=utf-8' \ --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE"'"}' \ https://slack.com/api/chat.postMessage - exit 1 - fi - displayName: Check 1.999.0 tag + curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ + -H 'Content-type: application/json; charset=utf-8' \ + --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$LINK"'"}' \ + https://slack.com/api/chat.postMessage -- bash: | - # Install build dependencies - (cd build && yarn) - node build/azure-pipelines/publish-types/check-version.js - displayName: Check version + curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ + -H 'Content-type: application/json; charset=utf-8' \ + --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE2"'"}' \ + https://slack.com/api/chat.postMessage -- bash: | - git config --global user.email "vscode@microsoft.com" - git config --global user.name "VSCode" - - git clone https://$(GITHUB_TOKEN)@github.com/DefinitelyTyped/DefinitelyTyped.git --depth=1 - node build/azure-pipelines/publish-types/update-types.js - - TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) - - cd DefinitelyTyped - - git diff --color | cat - git add -A - git status - git checkout -b "vscode-types-$TAG_VERSION" - git commit -m "VS Code $TAG_VERSION Extension API" - git push origin "vscode-types-$TAG_VERSION" - - displayName: Push update to DefinitelyTyped - -- bash: | - TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) - CHANNEL="G1C14HJ2F" - - MESSAGE="DefinitelyTyped/DefinitelyTyped#vscode-types-$TAG_VERSION created. Endgame master, please open this link, examine changes and create a PR:" - LINK="https://github.com/DefinitelyTyped/DefinitelyTyped/compare/vscode-types-$TAG_VERSION?quick_pull=1&body=Updating%20VS%20Code%20Extension%20API.%20See%20https%3A%2F%2Fgithub.com%2Fmicrosoft%2Fvscode%2Fissues%2F70175%20for%20details." - MESSAGE2="[@eamodio, @jrieken, @kmaetzel, @egamma]. Please review and merge PR to publish @types/vscode." - - curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ - -H 'Content-type: application/json; charset=utf-8' \ - --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE"'"}' \ - https://slack.com/api/chat.postMessage - - curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ - -H 'Content-type: application/json; charset=utf-8' \ - --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$LINK"'"}' \ - https://slack.com/api/chat.postMessage - - curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ - -H 'Content-type: application/json; charset=utf-8' \ - --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE2"'"}' \ - https://slack.com/api/chat.postMessage - - displayName: Send message on Slack + displayName: Send message on Slack diff --git a/build/azure-pipelines/release.yml b/build/azure-pipelines/release.yml index f5365b80c7e..edd293c04f6 100644 --- a/build/azure-pipelines/release.yml +++ b/build/azure-pipelines/release.yml @@ -1,22 +1,22 @@ steps: -- task: NodeTool@0 - inputs: - versionSpec: "10.x" + - task: NodeTool@0 + inputs: + versionSpec: "10.x" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- script: | - set -e + - script: | + set -e - (cd build ; yarn) + (cd build ; yarn) - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - node build/azure-pipelines/common/releaseBuild.js + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + node build/azure-pipelines/common/releaseBuild.js diff --git a/build/azure-pipelines/sync-mooncake.yml b/build/azure-pipelines/sync-mooncake.yml index 49dfc9ced80..280c9e6372d 100644 --- a/build/azure-pipelines/sync-mooncake.yml +++ b/build/azure-pipelines/sync-mooncake.yml @@ -1,24 +1,24 @@ steps: -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- script: | - set -e + - script: | + set -e - (cd build ; yarn) + (cd build ; yarn) - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - MOONCAKE_STORAGE_ACCESS_KEY="$(vscode-mooncake-storage-key)" \ - node build/azure-pipelines/common/sync-mooncake.js "$VSCODE_QUALITY" + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + MOONCAKE_STORAGE_ACCESS_KEY="$(vscode-mooncake-storage-key)" \ + node build/azure-pipelines/common/sync-mooncake.js "$VSCODE_QUALITY" diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index aded67174f4..23a755f3f6f 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -1,113 +1,116 @@ steps: -- script: | - mkdir -p .build - echo -n $BUILD_SOURCEVERSION > .build/commit - echo -n $VSCODE_QUALITY > .build/quality - displayName: Prepare cache flag + - script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + echo -n $VSCODE_QUALITY > .build/quality + displayName: Prepare cache flag -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/commit, .build/quality' - targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' - vstsFeed: 'npm-vscode' - platformIndependent: true - alias: 'Compilation' + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: "build/.cachesalt, .build/commit, .build/quality" + targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min" + vstsFeed: "npm-vscode" + platformIndependent: true + alias: "Compilation" -- script: | - set -e - exit 1 - displayName: Check RestoreCache - condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - script: | + set -e + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling -- script: | - set -e - git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" - git fetch distro - git merge $(node -p "require('./package.json').distro") - displayName: Merge distro + - script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro -# - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 -# inputs: -# keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' -# targetfolder: '**/node_modules, !**/node_modules/**/node_modules' -# vstsFeed: 'npm-vscode' + - script: | + npx https://aka.ms/enablesecurefeed standAlone + displayName: Switch to Terrapin packages -- script: | - set -e - CHILD_CONCURRENCY=1 yarn --frozen-lockfile - displayName: Install dependencies - # condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + # - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + # inputs: + # keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + # targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + # vstsFeed: 'npm-vscode' + - script: | + set -e + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + # condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -# - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 -# inputs: -# keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' -# targetfolder: '**/node_modules, !**/node_modules/**/node_modules' -# vstsFeed: 'npm-vscode' -# condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + # - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + # inputs: + # keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + # targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + # vstsFeed: 'npm-vscode' + # condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -# - script: | -# set -e -# yarn postinstall -# displayName: Run postinstall scripts -# condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + # - script: | + # set -e + # yarn postinstall + # displayName: Run postinstall scripts + # condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) -- script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality -- script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-web-min-ci - displayName: Build + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-web-min-ci + displayName: Build -- script: | - set -e - AZURE_STORAGE_ACCOUNT="$(web-storage-account)" \ - AZURE_STORAGE_ACCESS_KEY="$(web-storage-key)" \ - node build/azure-pipelines/upload-cdn.js - displayName: Upload to CDN + - script: | + set -e + AZURE_STORAGE_ACCOUNT="$(web-storage-account)" \ + AZURE_STORAGE_ACCESS_KEY="$(web-storage-key)" \ + node build/azure-pipelines/upload-cdn.js + displayName: Upload to CDN - # upload only the workbench.web.api.js source maps because - # we just compiled these bits in the previous step and the - # general task to upload source maps has already been run -- script: | - set -e - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ - node build/azure-pipelines/upload-sourcemaps out-vscode-web-min out-vscode-web-min/vs/workbench/workbench.web.api.js.map - displayName: Upload sourcemaps (Web) + # upload only the workbench.web.api.js source maps because + # we just compiled these bits in the previous step and the + # general task to upload source maps has already been run + - script: | + set -e + AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ + node build/azure-pipelines/upload-sourcemaps out-vscode-web-min out-vscode-web-min/vs/workbench/workbench.web.api.js.map + displayName: Upload sourcemaps (Web) -- script: | - set -e - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - ./build/azure-pipelines/web/publish.sh - displayName: Publish + - script: | + set -e + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + ./build/azure-pipelines/web/publish.sh + displayName: Publish diff --git a/build/azure-pipelines/win32/continuous-build-win32.yml b/build/azure-pipelines/win32/continuous-build-win32.yml index 6107eacc66c..7bd18707381 100644 --- a/build/azure-pipelines/win32/continuous-build-win32.yml +++ b/build/azure-pipelines/win32/continuous-build-win32.yml @@ -1,87 +1,87 @@ steps: -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: UsePythonVersion@0 - inputs: - versionSpec: '2.x' - addToPath: true + - task: UsePythonVersion@0 + inputs: + versionSpec: "2.x" + addToPath: true -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'vscode-build-cache' + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: ".yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "vscode-build-cache" -- powershell: | - yarn --frozen-lockfile - env: - CHILD_CONCURRENCY: "1" - displayName: Install Dependencies - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - powershell: | + yarn --frozen-lockfile + env: + CHILD_CONCURRENCY: "1" + displayName: Install Dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'vscode-build-cache' - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: ".yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "vscode-build-cache" + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn postinstall } - displayName: Run postinstall scripts - condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn postinstall } + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) -- powershell: | - yarn electron - displayName: Download Electron + - powershell: | + yarn electron + displayName: Download Electron -- powershell: | - yarn monaco-compile-check - displayName: Run Monaco Editor Checks + - powershell: | + yarn monaco-compile-check + displayName: Run Monaco Editor Checks -- script: | - yarn valid-layers-check - displayName: Run Valid Layers Checks + - script: | + yarn valid-layers-check + displayName: Run Valid Layers Checks -- powershell: | - yarn compile - displayName: Compile Sources + - powershell: | + yarn compile + displayName: Compile Sources -- powershell: | - yarn download-builtin-extensions - displayName: Download Built-in Extensions + - powershell: | + yarn download-builtin-extensions + displayName: Download Built-in Extensions -- powershell: | - .\scripts\test.bat --tfs "Unit Tests" - displayName: Run Unit Tests (Electron) + - powershell: | + .\scripts\test.bat --tfs "Unit Tests" + displayName: Run Unit Tests (Electron) -- powershell: | - yarn test-browser --browser chromium --browser firefox --tfs "Browser Unit Tests" - displayName: Run Unit Tests (Browser) + - powershell: | + yarn test-browser --browser chromium --browser firefox --tfs "Browser Unit Tests" + displayName: Run Unit Tests (Browser) -- powershell: | - .\scripts\test-integration.bat --tfs "Integration Tests" - displayName: Run Integration Tests (Electron) + - powershell: | + .\scripts\test-integration.bat --tfs "Integration Tests" + displayName: Run Integration Tests (Electron) -- task: PublishPipelineArtifact@0 - displayName: 'Publish Crash Reports' - inputs: - artifactName: crash-dump-windows - targetPath: .build\crashes - continueOnError: true - condition: failed() + - task: PublishPipelineArtifact@0 + displayName: "Publish Crash Reports" + inputs: + artifactName: crash-dump-windows + targetPath: .build\crashes + continueOnError: true + condition: failed() -- task: PublishTestResults@2 - displayName: Publish Tests Results - inputs: - testResultsFiles: '*-results.xml' - searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' - condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: "*-results.xml" + searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" + condition: succeededOrFailed() diff --git a/build/azure-pipelines/win32/product-build-win32-arm64.yml b/build/azure-pipelines/win32/product-build-win32-arm64.yml index 2e53167e613..9b75df2fd8d 100644 --- a/build/azure-pipelines/win32/product-build-win32-arm64.yml +++ b/build/azure-pipelines/win32/product-build-win32-arm64.yml @@ -1,192 +1,196 @@ steps: -- powershell: | - mkdir .build -ea 0 - "$env:BUILD_SOURCEVERSION" | Out-File -Encoding ascii -NoNewLine .build\commit - "$env:VSCODE_QUALITY" | Out-File -Encoding ascii -NoNewLine .build\quality - displayName: Prepare cache flag + - powershell: | + mkdir .build -ea 0 + "$env:BUILD_SOURCEVERSION" | Out-File -Encoding ascii -NoNewLine .build\commit + "$env:VSCODE_QUALITY" | Out-File -Encoding ascii -NoNewLine .build\quality + displayName: Prepare cache flag -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/commit, .build/quality' - targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' - vstsFeed: 'npm-vscode' - platformIndependent: true - alias: 'Compilation' + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: "build/.cachesalt, .build/commit, .build/quality" + targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min" + vstsFeed: "npm-vscode" + platformIndependent: true + alias: "Compilation" -- powershell: | - $ErrorActionPreference = "Stop" - exit 1 - displayName: Check RestoreCache - condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - powershell: | + $ErrorActionPreference = "Stop" + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: UsePythonVersion@0 - inputs: - versionSpec: '2.x' - addToPath: true + - task: UsePythonVersion@0 + inputs: + versionSpec: "2.x" + addToPath: true -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII - exec { git config user.email "vscode@microsoft.com" } - exec { git config user.name "VSCode" } + exec { git config user.email "vscode@microsoft.com" } + exec { git config user.name "VSCode" } - mkdir .build -ea 0 - "$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch - displayName: Prepare tooling + mkdir .build -ea 0 + "$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch + displayName: Prepare tooling -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" } - exec { git fetch distro } - exec { git merge $(node -p "require('./package.json').distro") } - displayName: Merge distro + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" } + exec { git fetch distro } + exec { git merge $(node -p "require('./package.json').distro") } + displayName: Merge distro -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' + - script: | + npx https://aka.ms/enablesecurefeed standAlone + displayName: Switch to Terrapin packages -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:npm_config_arch="$(VSCODE_ARCH)" - $env:CHILD_CONCURRENCY="1" - exec { yarn --frozen-lockfile } - displayName: Install dependencies - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: "build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:npm_config_arch="$(VSCODE_ARCH)" + $env:CHILD_CONCURRENCY="1" + exec { yarn --frozen-lockfile } + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn postinstall } - displayName: Run postinstall scripts - condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: "build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build/azure-pipelines/mixin } - displayName: Mix in quality + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn postinstall } + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" } - exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-code-helper" } - exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" } - displayName: Build + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/azure-pipelines/mixin } + displayName: Mix in quality -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - inputs: - ConnectedServiceName: 'ESRP CodeSign' - FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)' - Pattern: '*.dll,*.exe,*.node' - signConfigType: inlineSignParams - inlineOperation: | - [ - { - "keyCode": "CP-230012", - "operationSetCode": "SigntoolSign", - "parameters": [ - { - "parameterName": "OpusName", - "parameterValue": "VS Code" - }, - { - "parameterName": "OpusInfo", - "parameterValue": "https://code.visualstudio.com/" - }, - { - "parameterName": "Append", - "parameterValue": "/as" - }, - { - "parameterName": "FileDigest", - "parameterValue": "/fd \"SHA256\"" - }, - { - "parameterName": "PageHash", - "parameterValue": "/NPH" - }, - { - "parameterName": "TimeStamp", - "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" - } - ], - "toolName": "sign", - "toolVersion": "1.0" - }, - { - "keyCode": "CP-230012", - "operationSetCode": "SigntoolVerify", - "parameters": [ - { - "parameterName": "VerifyAll", - "parameterValue": "/all" - } - ], - "toolName": "sign", - "toolVersion": "1.0" - } - ] - SessionTimeout: 120 + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" } + exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-code-helper" } + exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" } + displayName: Build -- task: NuGetCommand@2 - displayName: Install ESRPClient.exe - inputs: - restoreSolution: 'build\azure-pipelines\win32\ESRPClient\packages.config' - feedsToUse: config - nugetConfigPath: 'build\azure-pipelines\win32\ESRPClient\NuGet.config' - externalFeedCredentials: 3fc0b7f7-da09-4ae7-a9c8-d69824b1819b - restoreDirectory: packages + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + inputs: + ConnectedServiceName: "ESRP CodeSign" + FolderPath: "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)" + Pattern: "*.dll,*.exe,*.node" + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "VS Code" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "https://code.visualstudio.com/" + }, + { + "parameterName": "Append", + "parameterValue": "/as" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd \"SHA256\"" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolVerify", + "parameters": [ + { + "parameterName": "VerifyAll", + "parameterValue": "/all" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 120 -- task: ESRPImportCertTask@1 - displayName: Import ESRP Request Signing Certificate - inputs: - ESRP: 'ESRP CodeSign' + - task: NuGetCommand@2 + displayName: Install ESRPClient.exe + inputs: + restoreSolution: 'build\azure-pipelines\win32\ESRPClient\packages.config' + feedsToUse: config + nugetConfigPath: 'build\azure-pipelines\win32\ESRPClient\NuGet.config' + externalFeedCredentials: 3fc0b7f7-da09-4ae7-a9c8-d69824b1819b + restoreDirectory: packages -- task: PowerShell@2 - inputs: - targetType: filePath - filePath: .\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 - arguments: "$(ESRP-SSL-AADAuth)" - displayName: Import ESRP Auth Certificate + - task: ESRPImportCertTask@1 + displayName: Import ESRP Request Signing Certificate + inputs: + ESRP: "ESRP CodeSign" -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)" - $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - .\build\azure-pipelines\win32\publish.ps1 - displayName: Publish + - task: PowerShell@2 + inputs: + targetType: filePath + filePath: .\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 + arguments: "$(ESRP-SSL-AADAuth)" + displayName: Import ESRP Auth Certificate -- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - continueOnError: true + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)" + $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + .\build\azure-pipelines\win32\publish.ps1 + displayName: Publish + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: "Component Detection" + continueOnError: true diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 43bd2479a4e..ce40e016fe7 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -1,254 +1,258 @@ steps: -- powershell: | - mkdir .build -ea 0 - "$env:BUILD_SOURCEVERSION" | Out-File -Encoding ascii -NoNewLine .build\commit - "$env:VSCODE_QUALITY" | Out-File -Encoding ascii -NoNewLine .build\quality - displayName: Prepare cache flag + - powershell: | + mkdir .build -ea 0 + "$env:BUILD_SOURCEVERSION" | Out-File -Encoding ascii -NoNewLine .build\commit + "$env:VSCODE_QUALITY" | Out-File -Encoding ascii -NoNewLine .build\quality + displayName: Prepare cache flag -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/commit, .build/quality' - targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' - vstsFeed: 'npm-vscode' - platformIndependent: true - alias: 'Compilation' + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: "build/.cachesalt, .build/commit, .build/quality" + targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min" + vstsFeed: "npm-vscode" + platformIndependent: true + alias: "Compilation" -- powershell: | - $ErrorActionPreference = "Stop" - exit 1 - displayName: Check RestoreCache - condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - powershell: | + $ErrorActionPreference = "Stop" + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) -- task: NodeTool@0 - inputs: - versionSpec: "12.14.1" + - task: NodeTool@0 + inputs: + versionSpec: "12.18.3" -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" -- task: UsePythonVersion@0 - inputs: - versionSpec: '2.x' - addToPath: true + - task: UsePythonVersion@0 + inputs: + versionSpec: "2.x" + addToPath: true -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII - exec { git config user.email "vscode@microsoft.com" } - exec { git config user.name "VSCode" } + exec { git config user.email "vscode@microsoft.com" } + exec { git config user.name "VSCode" } - mkdir .build -ea 0 - "$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch - displayName: Prepare tooling + mkdir .build -ea 0 + "$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch + displayName: Prepare tooling -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" } - exec { git fetch distro } - exec { git merge $(node -p "require('./package.json').distro") } - displayName: Merge distro + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" } + exec { git fetch distro } + exec { git merge $(node -p "require('./package.json').distro") } + displayName: Merge distro -- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' + - script: | + npx https://aka.ms/enablesecurefeed standAlone + displayName: Switch to Terrapin packages -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:npm_config_arch="$(VSCODE_ARCH)" - $env:CHILD_CONCURRENCY="1" - exec { yarn --frozen-lockfile } - displayName: Install dependencies - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: "build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" -- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 - inputs: - keyfile: 'build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' - targetfolder: '**/node_modules, !**/node_modules/**/node_modules' - vstsFeed: 'npm-vscode' - condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:npm_config_arch="$(VSCODE_ARCH)" + $env:CHILD_CONCURRENCY="1" + exec { yarn --frozen-lockfile } + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn postinstall } - displayName: Run postinstall scripts - condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: "build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock" + targetfolder: "**/node_modules, !**/node_modules/**/node_modules" + vstsFeed: "npm-vscode" + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build/azure-pipelines/mixin } - displayName: Mix in quality + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn postinstall } + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" } - exec { yarn gulp "vscode-reh-win32-$env:VSCODE_ARCH-min-ci" } - exec { yarn gulp "vscode-reh-web-win32-$env:VSCODE_ARCH-min-ci" } - exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-code-helper" } - exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" } - displayName: Build + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/azure-pipelines/mixin } + displayName: Mix in quality -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { yarn electron $(VSCODE_ARCH) } - exec { .\scripts\test.bat --build --tfs "Unit Tests" } - displayName: Run unit tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" } + exec { yarn gulp "vscode-reh-win32-$env:VSCODE_ARCH-min-ci" } + exec { yarn gulp "vscode-reh-web-win32-$env:VSCODE_ARCH-min-ci" } + exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-code-helper" } + exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" } + displayName: Build -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - 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')) + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn electron $(VSCODE_ARCH) } + exec { .\scripts\test.bat --build --tfs "Unit Tests" } + displayName: Run unit tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- powershell: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json - $AppNameShort = $AppProductJson.nameShort - exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-integration.bat --build --tfs "Integration Tests" } - displayName: Run integration tests (Electron) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + 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')) -- 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) - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - powershell: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json + $AppNameShort = $AppProductJson.nameShort + exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-integration.bat --build --tfs "Integration Tests" } + displayName: Run integration tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- 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) - 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) + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- task: PublishPipelineArtifact@0 - inputs: - artifactName: crash-dump-windows-$(VSCODE_ARCH) - targetPath: .build\crashes - displayName: 'Publish Crash Reports' - continueOnError: true - condition: failed() + - 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) + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- task: PublishTestResults@2 - displayName: Publish Tests Results - inputs: - testResultsFiles: '*-results.xml' - searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' - condition: succeededOrFailed() + - task: PublishPipelineArtifact@0 + inputs: + artifactName: crash-dump-windows-$(VSCODE_ARCH) + targetPath: .build\crashes + displayName: "Publish Crash Reports" + continueOnError: true + condition: failed() -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - inputs: - ConnectedServiceName: 'ESRP CodeSign' - FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH),$(agent.builddirectory)/vscode-reh-win32-$(VSCODE_ARCH)' - Pattern: '*.dll,*.exe,*.node' - signConfigType: inlineSignParams - inlineOperation: | - [ - { - "keyCode": "CP-230012", - "operationSetCode": "SigntoolSign", - "parameters": [ - { - "parameterName": "OpusName", - "parameterValue": "VS Code" - }, - { - "parameterName": "OpusInfo", - "parameterValue": "https://code.visualstudio.com/" - }, - { - "parameterName": "Append", - "parameterValue": "/as" - }, - { - "parameterName": "FileDigest", - "parameterValue": "/fd \"SHA256\"" - }, - { - "parameterName": "PageHash", - "parameterValue": "/NPH" - }, - { - "parameterName": "TimeStamp", - "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" - } - ], - "toolName": "sign", - "toolVersion": "1.0" - }, - { - "keyCode": "CP-230012", - "operationSetCode": "SigntoolVerify", - "parameters": [ - { - "parameterName": "VerifyAll", - "parameterValue": "/all" - } - ], - "toolName": "sign", - "toolVersion": "1.0" - } - ] - SessionTimeout: 120 + - task: PublishTestResults@2 + displayName: Publish Tests Results + inputs: + testResultsFiles: "*-results.xml" + searchFolder: "$(Build.ArtifactStagingDirectory)/test-results" + condition: succeededOrFailed() -- task: NuGetCommand@2 - displayName: Install ESRPClient.exe - inputs: - restoreSolution: 'build\azure-pipelines\win32\ESRPClient\packages.config' - feedsToUse: config - nugetConfigPath: 'build\azure-pipelines\win32\ESRPClient\NuGet.config' - externalFeedCredentials: 'ESRP Nuget' - restoreDirectory: packages + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + inputs: + ConnectedServiceName: "ESRP CodeSign" + FolderPath: "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH),$(agent.builddirectory)/vscode-reh-win32-$(VSCODE_ARCH)" + Pattern: "*.dll,*.exe,*.node" + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "VS Code" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "https://code.visualstudio.com/" + }, + { + "parameterName": "Append", + "parameterValue": "/as" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd \"SHA256\"" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolVerify", + "parameters": [ + { + "parameterName": "VerifyAll", + "parameterValue": "/all" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 120 -- task: ESRPImportCertTask@1 - displayName: Import ESRP Request Signing Certificate - inputs: - ESRP: 'ESRP CodeSign' + - task: NuGetCommand@2 + displayName: Install ESRPClient.exe + inputs: + restoreSolution: 'build\azure-pipelines\win32\ESRPClient\packages.config' + feedsToUse: config + nugetConfigPath: 'build\azure-pipelines\win32\ESRPClient\NuGet.config' + externalFeedCredentials: "ESRP Nuget" + restoreDirectory: packages -- task: PowerShell@2 - inputs: - targetType: filePath - filePath: .\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 - arguments: "$(ESRP-SSL-AADAuth)" - displayName: Import ESRP Auth Certificate + - task: ESRPImportCertTask@1 + displayName: Import ESRP Request Signing Certificate + inputs: + ESRP: "ESRP CodeSign" -- powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)" - $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - .\build\azure-pipelines\win32\publish.ps1 - displayName: Publish + - task: PowerShell@2 + inputs: + targetType: filePath + filePath: .\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 + arguments: "$(ESRP-SSL-AADAuth)" + displayName: Import ESRP Auth Certificate -- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - continueOnError: true + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)" + $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + .\build\azure-pipelines\win32\publish.ps1 + displayName: Publish + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: "Component Detection" + continueOnError: true diff --git a/build/darwin/sign.ts b/build/darwin/sign.ts index ee5d2eeb17b..538dc97adf1 100644 --- a/build/darwin/sign.ts +++ b/build/darwin/sign.ts @@ -13,6 +13,7 @@ import * as product from '../../product.json'; async function main(): Promise { const buildDir = process.env['AGENT_BUILDDIRECTORY']; const tempDir = process.env['AGENT_TEMPDIRECTORY']; + const arch = process.env['VSCODE_ARCH']; if (!buildDir) { throw new Error('$AGENT_BUILDDIRECTORY not set'); @@ -23,7 +24,7 @@ async function main(): Promise { } const baseDir = path.dirname(__dirname); - const appRoot = path.join(buildDir, 'VSCode-darwin'); + const appRoot = path.join(buildDir, `VSCode-darwin-${arch}`); const appName = product.nameLong + '.app'; const appFrameworkPath = path.join(appRoot, appName, 'Contents', 'Frameworks'); const helperAppBaseName = product.nameShort; diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 3c8bbe5b87f..4dbcd883f2e 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -326,7 +326,8 @@ const BUILD_TARGETS = [ { platform: 'win32', arch: 'ia32' }, { platform: 'win32', arch: 'x64' }, { platform: 'win32', arch: 'arm64' }, - { platform: 'darwin', arch: null, opts: { stats: true } }, + { platform: 'darwin', arch: 'x64', opts: { stats: true } }, + { platform: 'darwin', arch: 'arm64', opts: { stats: true } }, { platform: 'linux', arch: 'ia32' }, { platform: 'linux', arch: 'x64' }, { platform: 'linux', arch: 'armhf' }, diff --git a/cgmanifest.json b/cgmanifest.json index bd95a0d80b0..25cc4d5e980 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "chromium", "repositoryUrl": "https://chromium.googlesource.com/chromium/src", - "commitHash": "894fb9eb56c6cbda65e3c3ae9ada6d4cb5850cc9" + "commitHash": "0387c513f0319231a8ca6dd0a265102af3d4455e" } }, "licenseDetail": [ @@ -40,7 +40,7 @@ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ], "isOnlyProductionDependency": true, - "version": "83.0.4103.122" + "version": "87.0.4280.67" }, { "component": { @@ -48,11 +48,11 @@ "git": { "name": "nodejs", "repositoryUrl": "https://github.com/nodejs/node", - "commitHash": "9622fed3fb2cffcea9efff6c8cb4cc2def99d75d" + "commitHash": "e3e0927bb93ed92bcdfe81e7ad9af3d78ccc74fb" } }, "isOnlyProductionDependency": true, - "version": "12.14.1" + "version": "12.18.3" }, { "component": { @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "0b5f24002b4f18adee112ed39fe269aa51f6705c" + "commitHash": "edb67231577eb68eac1c955e271cb7a16f3eb1e3" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "9.3.3" + "version": "11.0.2" }, { "component": { diff --git a/extensions/debug-auto-launch/src/extension.ts b/extensions/debug-auto-launch/src/extension.ts index 5ae907a9dbe..440b3296e57 100644 --- a/extensions/debug-auto-launch/src/extension.ts +++ b/extensions/debug-auto-launch/src/extension.ts @@ -9,9 +9,13 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -const TEXT_ALWAYS = localize('status.text.auto.attach.always', 'Auto Attach: Always'); -const TEXT_SMART = localize('status.text.auto.attach.smart', 'Auto Attach: Smart'); -const TEXT_WITH_FLAG = localize('status.text.auto.attach.withFlag', 'Auto Attach: With Flag'); +const TEXT_STATUSBAR_LABEL = { + [State.Disabled]: localize('status.text.auto.attach.disabled', 'Auto Attach: Disabled'), + [State.Always]: localize('status.text.auto.attach.always', 'Auto Attach: Always'), + [State.Smart]: localize('status.text.auto.attach.smart', 'Auto Attach: Smart'), + [State.OnlyWithFlag]: localize('status.text.auto.attach.withFlag', 'Auto Attach: With Flag'), +}; + const TEXT_STATE_LABEL = { [State.Disabled]: localize('debug.javascript.autoAttach.disabled.label', 'Disabled'), [State.Always]: localize('debug.javascript.autoAttach.always.label', 'Always'), @@ -41,6 +45,9 @@ const TEXT_STATE_DESCRIPTION = { }; const TEXT_TOGGLE_WORKSPACE = localize('scope.workspace', 'Toggle auto attach in this workspace'); const TEXT_TOGGLE_GLOBAL = localize('scope.global', 'Toggle auto attach on this machine'); +const TEXT_TEMP_DISABLE = localize('tempDisable.disable', 'Temporarily disable auto attach in this session'); +const TEXT_TEMP_ENABLE = localize('tempDisable.enable', 'Re-enable auto attach'); +const TEXT_TEMP_DISABLE_LABEL = localize('tempDisable.suffix', 'Auto Attach: Disabled'); const TOGGLE_COMMAND = 'extension.node-debug.toggleAutoAttach'; const STORAGE_IPC = 'jsDebugIpcState'; @@ -65,12 +72,13 @@ const enum State { let currentState: Promise<{ context: vscode.ExtensionContext; state: State | null }>; let statusItem: vscode.StatusBarItem | undefined; // and there is no status bar item let server: Promise | undefined; // auto attach server +let isTemporarilyDisabled = false; // whether the auto attach server is disabled temporarily, reset whenever the state changes export function activate(context: vscode.ExtensionContext): void { currentState = Promise.resolve({ context, state: null }); context.subscriptions.push( - vscode.commands.registerCommand(TOGGLE_COMMAND, toggleAutoAttachSetting), + vscode.commands.registerCommand(TOGGLE_COMMAND, toggleAutoAttachSetting.bind(null, context)), ); context.subscriptions.push( @@ -108,24 +116,36 @@ function getDefaultScope(info: ReturnType { +async function toggleAutoAttachSetting(context: vscode.ExtensionContext, scope?: vscode.ConfigurationTarget): Promise { const section = vscode.workspace.getConfiguration(SETTING_SECTION); scope = scope || getDefaultScope(section.inspect(SETTING_STATE)); const isGlobalScope = scope === vscode.ConfigurationTarget.Global; - const quickPick = vscode.window.createQuickPick(); + const quickPick = vscode.window.createQuickPick(); const current = readCurrentState(); - quickPick.items = [State.Always, State.Smart, State.OnlyWithFlag, State.Disabled].map(state => ({ + const items: PickItem[] = [State.Always, State.Smart, State.OnlyWithFlag, State.Disabled].map(state => ({ state, label: TEXT_STATE_LABEL[state], description: TEXT_STATE_DESCRIPTION[state], alwaysShow: true, })); - quickPick.activeItems = quickPick.items.filter(i => i.state === current); + if (current !== State.Disabled) { + items.unshift({ + setTempDisabled: !isTemporarilyDisabled, + label: isTemporarilyDisabled ? TEXT_TEMP_ENABLE : TEXT_TEMP_DISABLE, + alwaysShow: true, + }); + } + + quickPick.items = items; + quickPick.activeItems = isTemporarilyDisabled + ? [items[0]] + : quickPick.items.filter(i => 'state' in i && i.state === current); quickPick.title = isGlobalScope ? TEXT_TOGGLE_GLOBAL : TEXT_TOGGLE_WORKSPACE; quickPick.buttons = [ { @@ -155,12 +175,23 @@ async function toggleAutoAttachSetting(scope?: vscode.ConfigurationTarget): Prom } if ('scope' in result) { - return await toggleAutoAttachSetting(result.scope); + return await toggleAutoAttachSetting(context, result.scope); } if ('state' in result) { section.update(SETTING_STATE, result.state, scope); } + + if ('setTempDisabled' in result) { + updateStatusBar(context, current, true); + isTemporarilyDisabled = result.setTempDisabled; + if (result.setTempDisabled) { + await destroyAttachServer(); + } else { + await createAttachServer(context); // unsets temp disabled var internally + } + updateStatusBar(context, current, false); + } } function readCurrentState(): State { @@ -168,26 +199,6 @@ function readCurrentState(): State { return section.get(SETTING_STATE) ?? State.Disabled; } -/** - * Makes sure the status bar exists and is visible. - */ -function ensureStatusBarExists(context: vscode.ExtensionContext) { - if (!statusItem) { - statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); - statusItem.command = TOGGLE_COMMAND; - statusItem.tooltip = localize( - 'status.tooltip.auto.attach', - 'Automatically attach to node.js processes in debug mode', - ); - statusItem.show(); - context.subscriptions.push(statusItem); - } else { - statusItem.show(); - } - - return statusItem; -} - async function clearJsDebugAttachState(context: vscode.ExtensionContext) { await context.workspaceState.update(STORAGE_IPC, undefined); await vscode.commands.executeCommand('extension.js-debug.clearAutoAttachVariables'); @@ -275,28 +286,46 @@ interface CachedIpcState { const transitions: { [S in State]: (context: vscode.ExtensionContext) => Promise } = { async [State.Disabled](context) { await clearJsDebugAttachState(context); - statusItem?.hide(); }, async [State.OnlyWithFlag](context) { await createAttachServer(context); - const statusItem = ensureStatusBarExists(context); - statusItem.text = TEXT_WITH_FLAG; }, async [State.Smart](context) { await createAttachServer(context); - const statusItem = ensureStatusBarExists(context); - statusItem.text = TEXT_SMART; }, async [State.Always](context) { await createAttachServer(context); - const statusItem = ensureStatusBarExists(context); - statusItem.text = TEXT_ALWAYS; }, }; +/** + * Ensures the status bar text reflects the current state. + */ +function updateStatusBar(context: vscode.ExtensionContext, state: State, busy = false) { + if (state === State.Disabled && !busy) { + statusItem?.hide(); + return; + } + + if (!statusItem) { + statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + statusItem.command = TOGGLE_COMMAND; + statusItem.tooltip = localize( + 'status.tooltip.auto.attach', + 'Automatically attach to node.js processes in debug mode', + ); + context.subscriptions.push(statusItem); + } + + let text = busy ? '$(loading) ' : ''; + text += isTemporarilyDisabled ? TEXT_TEMP_DISABLE_LABEL : TEXT_STATUSBAR_LABEL[state]; + statusItem.text = text; + statusItem.show(); +} + /** * Updates the auto attach feature based on the user or workspace setting */ @@ -306,7 +335,13 @@ function updateAutoAttach(newState: State) { return { context, state: oldState }; } + if (oldState !== null) { + updateStatusBar(context, oldState, true); + } + await transitions[newState](context); + isTemporarilyDisabled = false; + updateStatusBar(context, newState, false); return { context, state: newState }; }); } diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index a0a22505f85..12178fa8b56 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -1,461 +1,446 @@ { - "name": "emmet", - "displayName": "Emmet", - "description": "%description%", - "version": "1.0.0", - "publisher": "vscode", - "license": "MIT", - "engines": { - "vscode": "^1.13.0" - }, - "icon": "images/icon.png", - "categories": [ - "Other" - ], - "repository": { - "type": "git", - "url": "https://github.com/microsoft/vscode-emmet" - }, - "activationEvents": [ - "*", - "onCommand:emmet.expandAbbreviation", - "onLanguage:html", - "onLanguage:css", - "onLanguage:scss", - "onLanguage:less" - ], - "main": "./out/node/emmetNodeMain", - "browser": "./dist/browser/emmetBrowserMain", - "contributes": { - "configuration": { - "type": "object", - "title": "Emmet", - "properties": { - "emmet.showExpandedAbbreviation": { - "type": [ - "string" - ], - "enum": [ - "never", - "always", - "inMarkupAndStylesheetFilesOnly" - ], - "default": "always", - "markdownDescription": "%emmetShowExpandedAbbreviation%" - }, - "emmet.showAbbreviationSuggestions": { - "type": "boolean", - "default": true, - "markdownDescription": "%emmetShowAbbreviationSuggestions%" - }, - "emmet.includeLanguages": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "default": {}, - "markdownDescription": "%emmetIncludeLanguages%" - }, - "emmet.variables": { - "type": "object", - "properties": { - "lang": { - "type": "string", - "default": "en" - }, - "charset": { - "type": "string", - "default": "UTF-8" - } - }, - "default": {}, - "description": "%emmetVariables%" - }, - "emmet.syntaxProfiles": { - "type": "object", - "default": {}, - "description": "%emmetSyntaxProfiles%" - }, - "emmet.excludeLanguages": { - "type": "array", - "default": [ - "markdown" - ], - "description": "%emmetExclude%" - }, - "emmet.extensionsPath": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "%emmetExtensionsPath%" - }, - "emmet.triggerExpansionOnTab": { - "type": "boolean", - "default": false, - "description": "%emmetTriggerExpansionOnTab%" - }, - "emmet.preferences": { - "type": "object", - "default": {}, - "description": "%emmetPreferences%", - "properties": { - "css.intUnit": { - "type": "string", - "default": "px", - "description": "%emmetPreferencesIntUnit%" - }, - "css.floatUnit": { - "type": "string", - "default": "em", - "description": "%emmetPreferencesFloatUnit%" - }, - "css.propertyEnd": { - "type": "string", - "default": ";", - "description": "%emmetPreferencesCssAfter%" - }, - "sass.propertyEnd": { - "type": "string", - "default": "", - "description": "%emmetPreferencesSassAfter%" - }, - "stylus.propertyEnd": { - "type": "string", - "default": "", - "description": "%emmetPreferencesStylusAfter%" - }, - "css.valueSeparator": { - "type": "string", - "default": ": ", - "description": "%emmetPreferencesCssBetween%" - }, - "sass.valueSeparator": { - "type": "string", - "default": ": ", - "description": "%emmetPreferencesSassBetween%" - }, - "stylus.valueSeparator": { - "type": "string", - "default": " ", - "description": "%emmetPreferencesStylusBetween%" - }, - "bem.elementSeparator": { - "type": "string", - "default": "__", - "description": "%emmetPreferencesBemElementSeparator%" - }, - "bem.modifierSeparator": { - "type": "string", - "default": "_", - "description": "%emmetPreferencesBemModifierSeparator%" - }, - "filter.commentBefore": { - "type": "string", - "default": "", - "description": "%emmetPreferencesFilterCommentBefore%" - }, - "filter.commentAfter": { - "type": "string", - "default": "\n", - "description": "%emmetPreferencesFilterCommentAfter%" - }, - "filter.commentTrigger": { - "type": "array", - "default": [ - "id", - "class" - ], - "description": "%emmetPreferencesFilterCommentTrigger%" - }, - "format.noIndentTags": { - "type": "array", - "default": [ - "html" - ], - "description": "%emmetPreferencesFormatNoIndentTags%" - }, - "format.forceIndentationForTags": { - "type": "array", - "default": [ - "body" - ], - "description": "%emmetPreferencesFormatForceIndentTags%" - }, - "profile.allowCompactBoolean": { - "type": "boolean", - "default": false, - "description": "%emmetPreferencesAllowCompactBoolean%" - }, - "css.webkitProperties": { - "type": "string", - "default": null, - "markdownDescription": "%emmetPreferencesCssWebkitProperties%" - }, - "css.mozProperties": { - "type": "string", - "default": null, - "markdownDescription": "%emmetPreferencesCssMozProperties%" - }, - "css.oProperties": { - "type": "string", - "default": null, - "markdownDescription": "%emmetPreferencesCssOProperties%" - }, - "css.msProperties": { - "type": "string", - "default": null, - "markdownDescription": "%emmetPreferencesCssMsProperties%" - }, - "css.fuzzySearchMinScore": { - "type": "number", - "default": 0.3, - "description": "%emmetPreferencesCssFuzzySearchMinScore%" - } - } - }, - "emmet.showSuggestionsAsSnippets": { - "type": "boolean", - "default": false, - "markdownDescription": "%emmetShowSuggestionsAsSnippets%" - }, - "emmet.optimizeStylesheetParsing": { - "type": "boolean", - "default": true, - "markdownDescription": "%emmetOptimizeStylesheetParsing%" - } - } + "name": "emmet", + "displayName": "Emmet", + "description": "%description%", + "version": "1.0.0", + "publisher": "vscode", + "license": "MIT", + "engines": { + "vscode": "^1.13.0" }, - "commands": [ - { - "command": "editor.emmet.action.wrapIndividualLinesWithAbbreviation", - "title": "%command.wrapIndividualLinesWithAbbreviation%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.wrapWithAbbreviation", - "title": "%command.wrapWithAbbreviation%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.expandAbbreviation", - "title": "%command.expandAbbreviation%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.removeTag", - "title": "%command.removeTag%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.updateTag", - "title": "%command.updateTag%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.matchTag", - "title": "%command.matchTag%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.balanceIn", - "title": "%command.balanceIn%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.balanceOut", - "title": "%command.balanceOut%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.prevEditPoint", - "title": "%command.prevEditPoint%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.nextEditPoint", - "title": "%command.nextEditPoint%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.mergeLines", - "title": "%command.mergeLines%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.selectPrevItem", - "title": "%command.selectPrevItem%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.selectNextItem", - "title": "%command.selectNextItem%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.splitJoinTag", - "title": "%command.splitJoinTag%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.toggleComment", - "title": "%command.toggleComment%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.evaluateMathExpression", - "title": "%command.evaluateMathExpression%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.updateImageSize", - "title": "%command.updateImageSize%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.incrementNumberByOneTenth", - "title": "%command.incrementNumberByOneTenth%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.incrementNumberByOne", - "title": "%command.incrementNumberByOne%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.incrementNumberByTen", - "title": "%command.incrementNumberByTen%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.decrementNumberByOneTenth", - "title": "%command.decrementNumberByOneTenth%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.decrementNumberByOne", - "title": "%command.decrementNumberByOne%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.decrementNumberByTen", - "title": "%command.decrementNumberByTen%", - "category": "Emmet" - }, - { - "command": "editor.emmet.action.reflectCSSValue", - "title": "%command.reflectCSSValue%", - "category": "Emmet" - }, - { - "command": "workbench.action.showEmmetCommands", - "title": "%command.showEmmetCommands%", - "category": "" - } + "icon": "images/icon.png", + "categories": [ + "Other" ], - "keybindings": [ - { - "key": "tab", - "command": "editor.emmet.action.expandAbbreviation", - "when": "config.emmet.triggerExpansionOnTab && editorTextFocus && !editorReadonly && !editorTabMovesFocus" - } + "repository": { + "type": "git", + "url": "https://github.com/microsoft/vscode-emmet" + }, + "activationEvents": [ + "*", + "onCommand:emmet.expandAbbreviation", + "onLanguage:html", + "onLanguage:css", + "onLanguage:scss", + "onLanguage:less" ], - "menus": { - "commandPalette": [ - { - "command": "editor.emmet.action.wrapIndividualLinesWithAbbreviation" + "main": "./out/node/emmetNodeMain", + "browser": "./dist/browser/emmetBrowserMain", + "contributes": { + "configuration": { + "type": "object", + "title": "Emmet", + "properties": { + "emmet.showExpandedAbbreviation": { + "type": [ + "string" + ], + "enum": [ + "never", + "always", + "inMarkupAndStylesheetFilesOnly" + ], + "default": "always", + "markdownDescription": "%emmetShowExpandedAbbreviation%" + }, + "emmet.showAbbreviationSuggestions": { + "type": "boolean", + "default": true, + "markdownDescription": "%emmetShowAbbreviationSuggestions%" + }, + "emmet.includeLanguages": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "default": {}, + "markdownDescription": "%emmetIncludeLanguages%" + }, + "emmet.variables": { + "type": "object", + "properties": { + "lang": { + "type": "string", + "default": "en" + }, + "charset": { + "type": "string", + "default": "UTF-8" + } + }, + "default": {}, + "description": "%emmetVariables%" + }, + "emmet.syntaxProfiles": { + "type": "object", + "default": {}, + "description": "%emmetSyntaxProfiles%" + }, + "emmet.excludeLanguages": { + "type": "array", + "default": [ + "markdown" + ], + "description": "%emmetExclude%" + }, + "emmet.extensionsPath": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "%emmetExtensionsPath%" + }, + "emmet.triggerExpansionOnTab": { + "type": "boolean", + "default": false, + "description": "%emmetTriggerExpansionOnTab%" + }, + "emmet.preferences": { + "type": "object", + "default": {}, + "description": "%emmetPreferences%", + "properties": { + "css.intUnit": { + "type": "string", + "default": "px", + "description": "%emmetPreferencesIntUnit%" + }, + "css.floatUnit": { + "type": "string", + "default": "em", + "description": "%emmetPreferencesFloatUnit%" + }, + "css.propertyEnd": { + "type": "string", + "default": ";", + "description": "%emmetPreferencesCssAfter%" + }, + "sass.propertyEnd": { + "type": "string", + "default": "", + "description": "%emmetPreferencesSassAfter%" + }, + "stylus.propertyEnd": { + "type": "string", + "default": "", + "description": "%emmetPreferencesStylusAfter%" + }, + "css.valueSeparator": { + "type": "string", + "default": ": ", + "description": "%emmetPreferencesCssBetween%" + }, + "sass.valueSeparator": { + "type": "string", + "default": ": ", + "description": "%emmetPreferencesSassBetween%" + }, + "stylus.valueSeparator": { + "type": "string", + "default": " ", + "description": "%emmetPreferencesStylusBetween%" + }, + "bem.elementSeparator": { + "type": "string", + "default": "__", + "description": "%emmetPreferencesBemElementSeparator%" + }, + "bem.modifierSeparator": { + "type": "string", + "default": "_", + "description": "%emmetPreferencesBemModifierSeparator%" + }, + "filter.commentBefore": { + "type": "string", + "default": "", + "description": "%emmetPreferencesFilterCommentBefore%" + }, + "filter.commentAfter": { + "type": "string", + "default": "\n", + "description": "%emmetPreferencesFilterCommentAfter%" + }, + "filter.commentTrigger": { + "type": "array", + "default": [ + "id", + "class" + ], + "description": "%emmetPreferencesFilterCommentTrigger%" + }, + "format.noIndentTags": { + "type": "array", + "default": [ + "html" + ], + "description": "%emmetPreferencesFormatNoIndentTags%" + }, + "format.forceIndentationForTags": { + "type": "array", + "default": [ + "body" + ], + "description": "%emmetPreferencesFormatForceIndentTags%" + }, + "profile.allowCompactBoolean": { + "type": "boolean", + "default": false, + "description": "%emmetPreferencesAllowCompactBoolean%" + }, + "css.webkitProperties": { + "type": "string", + "default": null, + "markdownDescription": "%emmetPreferencesCssWebkitProperties%" + }, + "css.mozProperties": { + "type": "string", + "default": null, + "markdownDescription": "%emmetPreferencesCssMozProperties%" + }, + "css.oProperties": { + "type": "string", + "default": null, + "markdownDescription": "%emmetPreferencesCssOProperties%" + }, + "css.msProperties": { + "type": "string", + "default": null, + "markdownDescription": "%emmetPreferencesCssMsProperties%" + }, + "css.fuzzySearchMinScore": { + "type": "number", + "default": 0.3, + "description": "%emmetPreferencesCssFuzzySearchMinScore%" + } + } + }, + "emmet.showSuggestionsAsSnippets": { + "type": "boolean", + "default": false, + "markdownDescription": "%emmetShowSuggestionsAsSnippets%" + }, + "emmet.optimizeStylesheetParsing": { + "type": "boolean", + "default": true, + "markdownDescription": "%emmetOptimizeStylesheetParsing%" + } + } }, - { - "command": "editor.emmet.action.wrapWithAbbreviation" - }, - { - "command": "editor.emmet.action.expandAbbreviation" - }, - { - "command": "editor.emmet.action.removeTag" - }, - { - "command": "editor.emmet.action.updateTag" - }, - { - "command": "editor.emmet.action.matchTag" - }, - { - "command": "editor.emmet.action.balanceIn" - }, - { - "command": "editor.emmet.action.balanceOut" - }, - { - "command": "editor.emmet.action.prevEditPoint" - }, - { - "command": "editor.emmet.action.nextEditPoint" - }, - { - "command": "editor.emmet.action.mergeLines" - }, - { - "command": "editor.emmet.action.selectPrevItem" - }, - { - "command": "editor.emmet.action.selectNextItem" - }, - { - "command": "editor.emmet.action.splitJoinTag" - }, - { - "command": "editor.emmet.action.toggleComment" - }, - { - "command": "editor.emmet.action.evaluateMathExpression" - }, - { - "command": "editor.emmet.action.updateImageSize", - "when": "resourceScheme =~ /^file$/" - }, - { - "command": "editor.emmet.action.incrementNumberByOneTenth" - }, - { - "command": "editor.emmet.action.incrementNumberByOne" - }, - { - "command": "editor.emmet.action.incrementNumberByTen" - }, - { - "command": "editor.emmet.action.decrementNumberByOneTenth" - }, - { - "command": "editor.emmet.action.decrementNumberByOne" - }, - { - "command": "editor.emmet.action.decrementNumberByTen" - }, - { - "command": "editor.emmet.action.reflectCSSValue" + "commands": [ + { + "command": "editor.emmet.action.wrapIndividualLinesWithAbbreviation", + "title": "%command.wrapIndividualLinesWithAbbreviation%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.wrapWithAbbreviation", + "title": "%command.wrapWithAbbreviation%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.removeTag", + "title": "%command.removeTag%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.updateTag", + "title": "%command.updateTag%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.matchTag", + "title": "%command.matchTag%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.balanceIn", + "title": "%command.balanceIn%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.balanceOut", + "title": "%command.balanceOut%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.prevEditPoint", + "title": "%command.prevEditPoint%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.nextEditPoint", + "title": "%command.nextEditPoint%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.mergeLines", + "title": "%command.mergeLines%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.selectPrevItem", + "title": "%command.selectPrevItem%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.selectNextItem", + "title": "%command.selectNextItem%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.splitJoinTag", + "title": "%command.splitJoinTag%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.toggleComment", + "title": "%command.toggleComment%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.evaluateMathExpression", + "title": "%command.evaluateMathExpression%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.updateImageSize", + "title": "%command.updateImageSize%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.incrementNumberByOneTenth", + "title": "%command.incrementNumberByOneTenth%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.incrementNumberByOne", + "title": "%command.incrementNumberByOne%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.incrementNumberByTen", + "title": "%command.incrementNumberByTen%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.decrementNumberByOneTenth", + "title": "%command.decrementNumberByOneTenth%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.decrementNumberByOne", + "title": "%command.decrementNumberByOne%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.decrementNumberByTen", + "title": "%command.decrementNumberByTen%", + "category": "Emmet" + }, + { + "command": "editor.emmet.action.reflectCSSValue", + "title": "%command.reflectCSSValue%", + "category": "Emmet" + }, + { + "command": "workbench.action.showEmmetCommands", + "title": "%command.showEmmetCommands%", + "category": "" + } + ], + "menus": { + "commandPalette": [ + { + "command": "editor.emmet.action.wrapIndividualLinesWithAbbreviation" + }, + { + "command": "editor.emmet.action.wrapWithAbbreviation" + }, + { + "command": "editor.emmet.action.removeTag" + }, + { + "command": "editor.emmet.action.updateTag" + }, + { + "command": "editor.emmet.action.matchTag" + }, + { + "command": "editor.emmet.action.balanceIn" + }, + { + "command": "editor.emmet.action.balanceOut" + }, + { + "command": "editor.emmet.action.prevEditPoint" + }, + { + "command": "editor.emmet.action.nextEditPoint" + }, + { + "command": "editor.emmet.action.mergeLines" + }, + { + "command": "editor.emmet.action.selectPrevItem" + }, + { + "command": "editor.emmet.action.selectNextItem" + }, + { + "command": "editor.emmet.action.splitJoinTag" + }, + { + "command": "editor.emmet.action.toggleComment" + }, + { + "command": "editor.emmet.action.evaluateMathExpression" + }, + { + "command": "editor.emmet.action.updateImageSize", + "when": "resourceScheme =~ /^file$/" + }, + { + "command": "editor.emmet.action.incrementNumberByOneTenth" + }, + { + "command": "editor.emmet.action.incrementNumberByOne" + }, + { + "command": "editor.emmet.action.incrementNumberByTen" + }, + { + "command": "editor.emmet.action.decrementNumberByOneTenth" + }, + { + "command": "editor.emmet.action.decrementNumberByOne" + }, + { + "command": "editor.emmet.action.decrementNumberByTen" + }, + { + "command": "editor.emmet.action.reflectCSSValue" + } + ] } - ] + }, + "scripts": { + "watch": "gulp watch-extension:emmet", + "compile": "gulp compile-extension:emmet", + "deps": "yarn add vscode-emmet-helper" + }, + "devDependencies": { + "@types/node": "^12.11.7", + "mocha-junit-reporter": "^1.17.0", + "mocha-multi-reporters": "^1.1.7", + "vscode": "1.0.1" + }, + "dependencies": { + "@emmetio/css-parser": "ramya-rao-a/css-parser#vscode", + "@emmetio/html-matcher": "^0.3.3", + "@emmetio/math-expression": "^1.0.4", + "image-size": "^0.5.2", + "vscode-emmet-helper": "~2.0.0", + "vscode-html-languageservice": "^3.0.3" } - }, - "scripts": { - "watch": "gulp watch-extension:emmet", - "compile": "gulp compile-extension:emmet", - "deps": "yarn add vscode-emmet-helper" - }, - "devDependencies": { - "@types/node": "^12.11.7", - "mocha-junit-reporter": "^1.17.0", - "mocha-multi-reporters": "^1.1.7", - "vscode": "1.0.1" - }, - "dependencies": { - "@emmetio/css-parser": "ramya-rao-a/css-parser#vscode", - "@emmetio/html-matcher": "^0.3.3", - "@emmetio/math-expression": "^1.0.4", - "image-size": "^0.5.2", - "vscode-emmet-helper": "~2.0.0", - "vscode-html-languageservice": "^3.0.3" - } } diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index 4d4090c2b1f..2a1add8935e 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -2,7 +2,6 @@ "description": "Emmet support for VS Code", "command.wrapWithAbbreviation": "Wrap with Abbreviation", "command.wrapIndividualLinesWithAbbreviation": "Wrap Individual Lines with Abbreviation", - "command.expandAbbreviation": "Expand Abbreviation", "command.removeTag": "Remove Tag", "command.updateTag": "Update Tag", "command.matchTag": "Go to Matching Pair", diff --git a/extensions/emmet/src/emmetCommon.ts b/extensions/emmet/src/emmetCommon.ts index a458433057c..e768b03afd6 100644 --- a/extensions/emmet/src/emmetCommon.ts +++ b/extensions/emmet/src/emmetCommon.ts @@ -31,14 +31,10 @@ export function activateEmmetExtension(context: vscode.ExtensionContext) { wrapIndividualLinesWithAbbreviation(args); })); - context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.expandAbbreviationInternal', (args) => { + context.subscriptions.push(vscode.commands.registerCommand('emmet.expandAbbreviation', (args) => { expandEmmetAbbreviation(args); })); - context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.expandAbbreviation', () => { - vscode.commands.executeCommand('workbench.action.expandEmmetAbbreviation'); - })); - context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.removeTag', () => { return removeTag(); })); diff --git a/extensions/git/package.json b/extensions/git/package.json index b0ba9c45f74..bea5f96a67d 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -2262,31 +2262,36 @@ { "view": "scm", "contents": "%view.workbench.scm.empty%", - "when": "config.git.enabled && git.state == initialized && workbenchState == empty", + "when": "config.git.enabled && workbenchState == empty", + "enablement": "git.state == initialized", "group": "2_open@1" }, { "view": "scm", "contents": "%view.workbench.scm.folder%", - "when": "config.git.enabled && git.state == initialized && workbenchState == folder", + "when": "config.git.enabled && workbenchState == folder", + "enablement": "git.state == initialized", "group": "5_scm@1" }, { "view": "scm", "contents": "%view.workbench.scm.workspace%", - "when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount != 0", + "when": "config.git.enabled && workbenchState == workspace && workspaceFolderCount != 0", + "enablement": "git.state == initialized", "group": "5_scm@1" }, { "view": "scm", "contents": "%view.workbench.scm.emptyWorkspace%", - "when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount == 0", + "when": "config.git.enabled && workbenchState == workspace && workspaceFolderCount == 0", + "enablement": "git.state == initialized", "group": "2_open@1" }, { "view": "explorer", "contents": "%view.workbench.cloneRepository%", - "when": "config.git.enabled && git.state == initialized", + "when": "config.git.enabled", + "enablement": "git.state == initialized", "group": "5_scm@1" } ] diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 2ae28a0c17e..6158a7e0cd5 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -205,5 +205,5 @@ "view.workbench.scm.folder": "The folder currently open doesn't have a git repository. You can initialize a repository which will enable source control features powered by git.\n[Initialize Repository](command:git.init?%5Btrue%5D)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", "view.workbench.scm.workspace": "The workspace currently open doesn't have any folders containing git repositories. You can initialize a repository on a folder which will enable source control features powered by git.\n[Initialize Repository](command:git.init)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", "view.workbench.scm.emptyWorkspace": "The workspace currently open doesn't have any folders containing git repositories.\n[Add Folder to Workspace](command:workbench.action.addRootFolder)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", - "view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).\n[Clone Repository](command:git.clone)" + "view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).\n[Clone Repository](command:git.clone 'Clone a repository once the git extension has activated')" } diff --git a/extensions/html-language-features/server/src/modes/javascriptMode.ts b/extensions/html-language-features/server/src/modes/javascriptMode.ts index 086b8a906b8..1fc33faedec 100644 --- a/extensions/html-language-features/server/src/modes/javascriptMode.ts +++ b/extensions/html-language-features/server/src/modes/javascriptMode.ts @@ -6,7 +6,7 @@ import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; import { SymbolInformation, SymbolKind, CompletionItem, Location, SignatureHelp, SignatureInformation, ParameterInformation, - Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, MarkedString, + Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, DocumentHighlight, DocumentHighlightKind, CompletionList, Position, FormattingOptions, FoldingRange, FoldingRangeKind, SelectionRange, LanguageMode, Settings, SemanticTokenData, Workspace, DocumentContext } from './languageModes'; @@ -142,10 +142,10 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache { ]; await assertTokens(input, [ t(3, 11, 3, 'function.declaration'), t(3, 15, 2, 'parameter.declaration'), - t(4, 11, 3, 'function'), t(4, 15, 4, 'interface'), t(4, 20, 3, 'member'), t(4, 24, 2, 'parameter'), - t(6, 6, 6, 'variable'), t(6, 13, 8, 'property'), t(6, 24, 5, 'member'), t(6, 35, 7, 'member'), t(6, 43, 1, 'parameter.declaration'), t(6, 48, 3, 'function'), t(6, 52, 1, 'parameter') + t(4, 11, 3, 'function'), t(4, 15, 4, 'interface'), t(4, 20, 3, 'method'), t(4, 24, 2, 'parameter'), + t(6, 6, 6, 'variable'), t(6, 13, 8, 'property'), t(6, 24, 5, 'method'), t(6, 35, 7, 'method'), t(6, 43, 1, 'parameter.declaration'), t(6, 48, 3, 'function'), t(6, 52, 1, 'parameter') ]); }); @@ -115,9 +115,9 @@ suite('HTML Semantic Tokens', () => { t(3, 8, 1, 'class.declaration'), t(4, 11, 1, 'property.declaration.static'), t(5, 4, 1, 'property.declaration'), - t(6, 10, 1, 'member.declaration.async'), t(6, 23, 1, 'class'), t(6, 25, 1, 'property.static'), t(6, 40, 1, 'member.async'), + t(6, 10, 1, 'method.declaration.async'), t(6, 23, 1, 'class'), t(6, 25, 1, 'property.static'), t(6, 40, 1, 'method.async'), t(7, 8, 1, 'property.declaration'), t(7, 26, 1, 'property'), - t(8, 11, 1, 'member.declaration.static'), t(8, 28, 1, 'class'), t(8, 32, 1, 'property'), + t(8, 11, 1, 'method.declaration.static'), t(8, 28, 1, 'class'), t(8, 32, 1, 'property'), ]); }); @@ -157,7 +157,7 @@ suite('HTML Semantic Tokens', () => { t(3, 8, 1, 'variable.declaration.readonly'), t(4, 8, 1, 'class.declaration'), t(4, 28, 1, 'property.declaration.static.readonly'), t(4, 42, 3, 'property.declaration.static'), t(4, 47, 3, 'interface'), t(5, 13, 1, 'enum.declaration'), t(5, 17, 1, 'property.declaration.readonly'), t(5, 24, 1, 'property.declaration.readonly'), t(5, 28, 1, 'property.readonly'), - t(6, 2, 7, 'variable'), t(6, 10, 3, 'member'), t(6, 14, 1, 'variable.readonly'), t(6, 18, 1, 'class'), t(6, 20, 1, 'property.static.readonly'), t(6, 24, 1, 'class'), t(6, 26, 3, 'property.static'), t(6, 30, 6, 'property.readonly'), + t(6, 2, 7, 'variable'), t(6, 10, 3, 'method'), t(6, 14, 1, 'variable.readonly'), t(6, 18, 1, 'class'), t(6, 20, 1, 'property.static.readonly'), t(6, 24, 1, 'class'), t(6, 26, 3, 'property.static'), t(6, 30, 6, 'property.readonly'), ]); }); @@ -197,7 +197,7 @@ suite('HTML Semantic Tokens', () => { ]; await assertTokens(input, [ t(3, 11, 1, 'function.declaration'), t(3, 13, 1, 'typeParameter.declaration'), t(3, 16, 2, 'parameter.declaration'), t(3, 20, 1, 'typeParameter'), t(3, 24, 1, 'typeParameter'), t(3, 39, 2, 'parameter'), - t(6, 2, 6, 'variable'), t(6, 9, 5, 'member') + t(6, 2, 6, 'variable'), t(6, 9, 5, 'method') ]); }); @@ -215,7 +215,7 @@ suite('HTML Semantic Tokens', () => { /*9*/'', ]; await assertTokens(input, [ - t(3, 2, 6, 'variable'), t(3, 9, 5, 'member') + t(3, 2, 6, 'variable'), t(3, 9, 5, 'method') ], [Range.create(Position.create(2, 0), Position.create(4, 0))]); await assertTokens(input, [ diff --git a/extensions/javascript/snippets/javascript.code-snippets b/extensions/javascript/snippets/javascript.code-snippets index b005c80c844..a48a64c2813 100644 --- a/extensions/javascript/snippets/javascript.code-snippets +++ b/extensions/javascript/snippets/javascript.code-snippets @@ -35,7 +35,7 @@ "prefix": "forin", "body": [ "for (const ${1:key} in ${2:object}) {", - "\tif (${2:object}.hasOwnProperty(${1:key})) {", + "\tif (Object.hasOwnProperty.call(${2:object}, ${1:key})) {", "\t\tconst ${3:element} = ${2:object}[${1:key}];", "\t\t$0", "\t}", diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 2f53537dfe9..b7f499afb86 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -197,6 +197,12 @@ "description": "%typescript.implementationsCodeLens.enabled%", "scope": "window" }, + "typescript.tsserver.enableTracing": { + "type": "boolean", + "default": false, + "description": "%typescript.tsserver.enableTracing%", + "scope": "window" + }, "typescript.tsserver.log": { "type": "string", "enum": [ diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index 5ddd514e16b..4283596c2ff 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -8,6 +8,7 @@ "typescript.tsdk.desc": "Specifies the folder path to the tsserver and lib*.d.ts files under a TypeScript install to use for IntelliSense, for example: `./node_modules/typescript/lib`.\n\n- When specified as a user setting, the TypeScript version from `typescript.tsdk` automatically replaces the built-in TypeScript version.\n- When specified as a workspace setting, `typescript.tsdk` allows you to switch to use that workspace version of TypeScript for IntelliSense with the `TypeScript: Select TypeScript version` command.\n\nSee the [TypeScript documentation](https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-newer-typescript-versions) for more detail about managing TypeScript versions.", "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.enableTracing": "Enables tracing TS server performance to a directory. These trace files can be used to diagnose TS Server performance issues. The log may contain file paths, source code, and other potentially sensitive information from your project.", "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.", "typescript.tsserver.pluginPaths.item": "Either an absolute or relative path. Relative path will be resolved against workspace folder(s).", diff --git a/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts b/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts index 202ed4d4ae1..16f78dbe486 100644 --- a/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts +++ b/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts @@ -174,7 +174,7 @@ tokenTypes[TokenType.variable] = 'variable'; tokenTypes[TokenType.enumMember] = 'enumMember'; tokenTypes[TokenType.property] = 'property'; tokenTypes[TokenType.function] = 'function'; -tokenTypes[TokenType.member] = 'member'; +tokenTypes[TokenType.member] = 'method'; const tokenModifiers: string[] = []; tokenModifiers[TokenModifier.async] = 'async'; diff --git a/extensions/typescript-language-features/src/tsServer/spawner.ts b/extensions/typescript-language-features/src/tsServer/spawner.ts index a3ad0abb1c7..58fd431edc7 100644 --- a/extensions/typescript-language-features/src/tsServer/spawner.ts +++ b/extensions/typescript-language-features/src/tsServer/spawner.ts @@ -128,7 +128,7 @@ export class TypeScriptServerSpawner { const apiVersion = version.apiVersion || API.defaultVersion; const canceller = cancellerFactory.create(kind, this._tracer); - const { args, tsServerLogFile } = this.getTsServerArgs(kind, configuration, version, apiVersion, pluginManager, canceller.cancellationPipeName); + const { args, tsServerLogFile, tsServerTraceDirectory } = this.getTsServerArgs(kind, configuration, version, apiVersion, pluginManager, canceller.cancellationPipeName); if (TypeScriptServerSpawner.isLoggingEnabled(configuration)) { if (tsServerLogFile) { @@ -138,6 +138,14 @@ export class TypeScriptServerSpawner { } } + if (configuration.enableTsServerTracing) { + if (tsServerTraceDirectory) { + this._logger.info(`<${kind}> Trace directory: ${tsServerTraceDirectory}`); + } else { + this._logger.error(`<${kind}> Could not create trace directory`); + } + } + this._logger.info(`<${kind}> Forking...`); const process = this._factory.fork(version.tsServerPath, args, kind, configuration, this._versionManager); this._logger.info(`<${kind}> Starting...`); @@ -173,9 +181,10 @@ export class TypeScriptServerSpawner { apiVersion: API, pluginManager: PluginManager, cancellationPipeName: string | undefined, - ): { args: string[], tsServerLogFile: string | undefined } { + ): { args: string[], tsServerLogFile: string | undefined, tsServerTraceDirectory: string | undefined } { const args: string[] = []; let tsServerLogFile: string | undefined; + let tsServerTraceDirectory: string | undefined; if (kind === TsServerProcessKind.Syntax) { if (apiVersion.gte(API.v401)) { @@ -216,6 +225,13 @@ export class TypeScriptServerSpawner { } } + if (configuration.enableTsServerTracing && !isWeb()) { + tsServerTraceDirectory = this._logDirectoryProvider.getNewLogDirectory(); + if (tsServerTraceDirectory) { + args.push('--traceDirectory', tsServerTraceDirectory); + } + } + if (!isWeb()) { const pluginPaths = this._pluginPathsProvider.getPluginPaths(); @@ -251,7 +267,7 @@ export class TypeScriptServerSpawner { args.push('--validateDefaultNpmLocation'); } - return { args, tsServerLogFile }; + return { args, tsServerLogFile, tsServerTraceDirectory }; } private static isLoggingEnabled(configuration: TypeScriptServiceConfiguration) { diff --git a/extensions/typescript-language-features/src/utils/configuration.ts b/extensions/typescript-language-features/src/utils/configuration.ts index 9cf827fb5d5..529ba2f3f8f 100644 --- a/extensions/typescript-language-features/src/utils/configuration.ts +++ b/extensions/typescript-language-features/src/utils/configuration.ts @@ -102,6 +102,7 @@ export class TypeScriptServiceConfiguration { public readonly enablePromptUseWorkspaceTsdk: boolean; public readonly watchOptions: protocol.WatchOptions | undefined; public readonly includePackageJsonAutoImports: 'auto' | 'on' | 'off' | undefined; + public readonly enableTsServerTracing: boolean; public static loadFromWorkspace(): TypeScriptServiceConfiguration { return new TypeScriptServiceConfiguration(); @@ -124,6 +125,7 @@ export class TypeScriptServiceConfiguration { this.enablePromptUseWorkspaceTsdk = TypeScriptServiceConfiguration.readEnablePromptUseWorkspaceTsdk(configuration); this.watchOptions = TypeScriptServiceConfiguration.readWatchOptions(configuration); this.includePackageJsonAutoImports = TypeScriptServiceConfiguration.readIncludePackageJsonAutoImports(configuration); + this.enableTsServerTracing = TypeScriptServiceConfiguration.readEnableTsServerTracing(configuration); } public isEqualTo(other: TypeScriptServiceConfiguration): boolean { @@ -210,4 +212,8 @@ export class TypeScriptServiceConfiguration { private static readEnablePromptUseWorkspaceTsdk(configuration: vscode.WorkspaceConfiguration): boolean { return configuration.get('typescript.enablePromptUseWorkspaceTsdk', false); } + + private static readEnableTsServerTracing(configuration: vscode.WorkspaceConfiguration): boolean { + return configuration.get('typescript.tsserver.enableTracing', false); + } } diff --git a/package.json b/package.json index 2e40d6c7161..37c7917ca23 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.52.0", - "distro": "eec03a44a38591e43680fe058326dbf2d2015518", + "distro": "645d71eca7b3cb5addb7e2251dd11a1af5f5fbc5", "author": { "name": "Microsoft Corporation" }, @@ -44,7 +44,8 @@ "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" + "eslint": "eslint -c .eslintrc.json --rulesdir ./build/lib/eslint --ext .ts --ext .js ./src/vs ./extensions", + "electron-rebuild": "electron-rebuild --arch=arm64 --force --version=11.0.2" }, "dependencies": { "applicationinsights": "1.0.8", @@ -59,7 +60,7 @@ "native-is-elevated": "0.4.1", "native-keymap": "2.2.1", "native-watchdog": "1.3.0", - "node-pty": "0.10.0-beta17", + "node-pty": "0.10.0-beta18", "spdlog": "^0.11.1", "sudo-prompt": "9.1.1", "tas-client-umd": "0.1.2", @@ -111,7 +112,8 @@ "css-loader": "^3.2.0", "debounce": "^1.0.0", "deemon": "^1.4.0", - "electron": "9.3.3", + "electron": "11.0.2", + "electron-rebuild": "2.0.3", "eslint": "6.8.0", "eslint-plugin-jsdoc": "^19.1.0", "eslint-plugin-mocha": "8.0.0", @@ -189,7 +191,7 @@ "url": "https://github.com/microsoft/vscode/issues" }, "optionalDependencies": { - "vscode-windows-ca-certs": "0.2.0", + "vscode-windows-ca-certs": "^0.3.0", "vscode-windows-registry": "1.0.3", "windows-foreground-love": "0.2.0", "windows-mutex": "0.3.0", diff --git a/remote/.yarnrc b/remote/.yarnrc index c1a32ce532a..cd436416b56 100644 --- a/remote/.yarnrc +++ b/remote/.yarnrc @@ -1,3 +1,3 @@ disturl "http://nodejs.org/dist" -target "12.14.1" +target "12.18.3" runtime "node" diff --git a/remote/package.json b/remote/package.json index f68deac647c..57710a189ba 100644 --- a/remote/package.json +++ b/remote/package.json @@ -12,15 +12,15 @@ "jschardet": "2.2.1", "minimist": "^1.2.5", "native-watchdog": "1.3.0", - "node-pty": "0.10.0-beta17", + "node-pty": "0.10.0-beta18", "spdlog": "^0.11.1", "tas-client-umd": "0.1.2", "vscode-nsfw": "1.2.9", "vscode-oniguruma": "1.3.1", "vscode-proxy-agent": "^0.5.2", + "vscode-regexpp": "^3.1.0", "vscode-ripgrep": "^1.11.1", "vscode-textmate": "5.2.0", - "vscode-regexpp": "^3.1.0", "xterm": "4.10.0-beta.4", "xterm-addon-search": "0.8.0-beta.3", "xterm-addon-unicode11": "0.3.0-beta.3", @@ -29,7 +29,7 @@ "yazl": "^2.4.3" }, "optionalDependencies": { - "vscode-windows-ca-certs": "0.2.0", + "vscode-windows-ca-certs": "0.3.0", "vscode-windows-registry": "1.0.2" } } diff --git a/remote/yarn.lock b/remote/yarn.lock index 2647e384aba..e15eb9d9839 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -167,11 +167,16 @@ glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" -graceful-fs@4.2.3, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== +graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + 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" @@ -279,7 +284,12 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -nan@^2.10.0, nan@^2.14.0: +nan@^2.10.0: + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + +nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -289,15 +299,15 @@ native-watchdog@1.3.0: resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.3.0.tgz#88cee94c9dc766b85c8506eda14c8bd8c9618e27" integrity sha512-WOjGRNGkYZ5MXsntcvCYrKtSYMaewlbCFplbcUVo9bE80LPVt8TAVFHYWB8+a6fWCGYheq21+Wtt6CJrUaCJhw== -node-addon-api@1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217" - integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA== +node-addon-api@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.2.tgz#04bc7b83fd845ba785bb6eae25bc857e1ef75681" + integrity sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg== -node-pty@0.10.0-beta17: - version "0.10.0-beta17" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta17.tgz#962d4a3f4dc6772385e0cad529c209cef3bc79e6" - integrity sha512-tn7EANQacnAvnOQCImvgag1DL0tVmUoY/1yIZbh3u/BBpvCcGHLZJNn7TXheodRLr6hmGSUS2VbfcUr9p0gOug== +node-pty@0.10.0-beta18: + version "0.10.0-beta18" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta18.tgz#7ed2d3f4a06b2b23fe2abdf5b41655e9dffc25d5" + integrity sha512-vpK4yB3A3VzgkvdOWegL7GcPapt45jfA4b3ejUe8k4RmqdWBRvFJngew8T3qAxmLhTkfo93psaN6izTlfkc6FA== dependencies: nan "^2.14.0" @@ -428,12 +438,12 @@ vscode-textmate@5.2.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== -vscode-windows-ca-certs@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.2.0.tgz#086f0f4de57e2760a35ac6920831bff246237115" - integrity sha512-YBrJRT0zos+Yb1Qdn73GD8QZr7pa2IE96b5Y1hmmp6XeR8aYB7Iiq5gDAF/+/AxL+caSR9KPZQ6jiYWh5biD7w== +vscode-windows-ca-certs@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.3.0.tgz#324e1f8ba842bbf048a39e7c0ee8fe655e9adfcc" + integrity sha512-CYrpCEKmAFQJoZNReOrelNL+VKyebOVRCqL9evrBlVcpWQDliliJgU5RggGS8FPGtQ3jAKLQt9frF0qlxYYPKA== dependencies: - node-addon-api "1.6.2" + node-addon-api "^3.0.2" vscode-windows-registry@1.0.2: version "1.0.2" diff --git a/resources/linux/rpm/dependencies.json b/resources/linux/rpm/dependencies.json index 7f95cd3e5db..dec9b480689 100644 --- a/resources/linux/rpm/dependencies.json +++ b/resources/linux/rpm/dependencies.json @@ -66,133 +66,133 @@ "libgbm.so.1()(64bit)" ], "aarch64": [ - "libpthread.so.0()(aarch64)", - "libpthread.so.0(GLIBC_2.2.5)(aarch64)", - "libpthread.so.0(GLIBC_2.3.2)(aarch64)", - "libpthread.so.0(GLIBC_2.3.3)(aarch64)", - "libgtk-3.so.0()(aarch64)", - "libgdk-x11-2.0.so.0()(aarch64)", - "libatk-1.0.so.0()(aarch64)", - "libgio-2.0.so.0()(aarch64)", - "libpangocairo-1.0.so.0()(aarch64)", - "libgdk_pixbuf-2.0.so.0()(aarch64)", - "libcairo.so.2()(aarch64)", - "libpango-1.0.so.0()(aarch64)", - "libfreetype.so.6()(aarch64)", - "libfontconfig.so.1()(aarch64)", - "libgobject-2.0.so.0()(aarch64)", - "libdbus-1.so.3()(aarch64)", - "libXi.so.6()(aarch64)", - "libXcursor.so.1()(aarch64)", - "libXdamage.so.1()(aarch64)", - "libXrandr.so.2()(aarch64)", - "libXcomposite.so.1()(aarch64)", - "libXext.so.6()(aarch64)", - "libXfixes.so.3()(aarch64)", - "libXrender.so.1()(aarch64)", - "libX11.so.6()(aarch64)", - "libXss.so.1()(aarch64)", - "libXtst.so.6()(aarch64)", - "libgmodule-2.0.so.0()(aarch64)", - "librt.so.1()(aarch64)", - "libglib-2.0.so.0()(aarch64)", - "libnss3.so()(aarch64)", - "libnssutil3.so()(aarch64)", - "libsmime3.so()(aarch64)", - "libnspr4.so()(aarch64)", - "libasound.so.2()(aarch64)", - "libcups.so.2()(aarch64)", - "libdl.so.2()(aarch64)", - "libexpat.so.1()(aarch64)", - "libstdc++.so.6()(aarch64)", - "libstdc++.so.6(GLIBCXX_3.4)(aarch64)", - "libstdc++.so.6(GLIBCXX_3.4.10)(aarch64)", - "libstdc++.so.6(GLIBCXX_3.4.11)(aarch64)", - "libstdc++.so.6(GLIBCXX_3.4.14)(aarch64)", - "libstdc++.so.6(GLIBCXX_3.4.15)(aarch64)", - "libstdc++.so.6(GLIBCXX_3.4.9)(aarch64)", - "libm.so.6()(aarch64)", - "libm.so.6(GLIBC_2.2.5)(aarch64)", - "libgcc_s.so.1()(aarch64)", - "libgcc_s.so.1(GCC_3.0)(aarch64)", - "libgcc_s.so.1(GCC_4.0.0)(aarch64)", - "libc.so.6()(aarch64)", - "libc.so.6(GLIBC_2.11)(aarch64)", - "libc.so.6(GLIBC_2.2.5)(aarch64)", - "libc.so.6(GLIBC_2.3)(aarch64)", - "libc.so.6(GLIBC_2.3.2)(aarch64)", - "libc.so.6(GLIBC_2.3.4)(aarch64)", - "libc.so.6(GLIBC_2.4)(aarch64)", - "libc.so.6(GLIBC_2.6)(aarch64)", - "libc.so.6(GLIBC_2.7)(aarch64)", - "libc.so.6(GLIBC_2.9)(aarch64)", - "libxcb.so.1()(aarch64)", - "libxkbfile.so.1()(aarch64)", - "libsecret-1.so.0()(aarch64)" + "libpthread.so.0()(64bit)", + "libpthread.so.0(GLIBC_2.2.5)(64bit)", + "libpthread.so.0(GLIBC_2.3.2)(64bit)", + "libpthread.so.0(GLIBC_2.3.3)(64bit)", + "libgtk-3.so.0()(64bit)", + "libgdk-x11-2.0.so.0()(64bit)", + "libatk-1.0.so.0()(64bit)", + "libgio-2.0.so.0()(64bit)", + "libpangocairo-1.0.so.0()(64bit)", + "libgdk_pixbuf-2.0.so.0()(64bit)", + "libcairo.so.2()(64bit)", + "libpango-1.0.so.0()(64bit)", + "libfreetype.so.6()(64bit)", + "libfontconfig.so.1()(64bit)", + "libgobject-2.0.so.0()(64bit)", + "libdbus-1.so.3()(64bit)", + "libXi.so.6()(64bit)", + "libXcursor.so.1()(64bit)", + "libXdamage.so.1()(64bit)", + "libXrandr.so.2()(64bit)", + "libXcomposite.so.1()(64bit)", + "libXext.so.6()(64bit)", + "libXfixes.so.3()(64bit)", + "libXrender.so.1()(64bit)", + "libX11.so.6()(64bit)", + "libXss.so.1()(64bit)", + "libXtst.so.6()(64bit)", + "libgmodule-2.0.so.0()(64bit)", + "librt.so.1()(64bit)", + "libglib-2.0.so.0()(64bit)", + "libnss3.so()(64bit)", + "libnssutil3.so()(64bit)", + "libsmime3.so()(64bit)", + "libnspr4.so()(64bit)", + "libasound.so.2()(64bit)", + "libcups.so.2()(64bit)", + "libdl.so.2()(64bit)", + "libexpat.so.1()(64bit)", + "libstdc++.so.6()(64bit)", + "libstdc++.so.6(GLIBCXX_3.4)(64bit)", + "libstdc++.so.6(GLIBCXX_3.4.10)(64bit)", + "libstdc++.so.6(GLIBCXX_3.4.11)(64bit)", + "libstdc++.so.6(GLIBCXX_3.4.14)(64bit)", + "libstdc++.so.6(GLIBCXX_3.4.15)(64bit)", + "libstdc++.so.6(GLIBCXX_3.4.9)(64bit)", + "libm.so.6()(64bit)", + "libm.so.6(GLIBC_2.2.5)(64bit)", + "libgcc_s.so.1()(64bit)", + "libgcc_s.so.1(GCC_3.0)(64bit)", + "libgcc_s.so.1(GCC_4.0.0)(64bit)", + "libc.so.6()(64bit)", + "libc.so.6(GLIBC_2.11)(64bit)", + "libc.so.6(GLIBC_2.2.5)(64bit)", + "libc.so.6(GLIBC_2.3)(64bit)", + "libc.so.6(GLIBC_2.3.2)(64bit)", + "libc.so.6(GLIBC_2.3.4)(64bit)", + "libc.so.6(GLIBC_2.4)(64bit)", + "libc.so.6(GLIBC_2.6)(64bit)", + "libc.so.6(GLIBC_2.7)(64bit)", + "libc.so.6(GLIBC_2.9)(64bit)", + "libxcb.so.1()(64bit)", + "libxkbfile.so.1()(64bit)", + "libsecret-1.so.0()(64bit)" ], "armv7hl": [ - "libpthread.so.0()(armv7hl)", - "libpthread.so.0(GLIBC_2.2.5)(armv7hl)", - "libpthread.so.0(GLIBC_2.3.2)(armv7hl)", - "libpthread.so.0(GLIBC_2.3.3)(armv7hl)", - "libgtk-3.so.0()(armv7hl)", - "libgdk-x11-2.0.so.0()(armv7hl)", - "libatk-1.0.so.0()(armv7hl)", - "libgio-2.0.so.0()(armv7hl)", - "libpangocairo-1.0.so.0()(armv7hl)", - "libgdk_pixbuf-2.0.so.0()(armv7hl)", - "libcairo.so.2()(armv7hl)", - "libpango-1.0.so.0()(armv7hl)", - "libfreetype.so.6()(armv7hl)", - "libfontconfig.so.1()(armv7hl)", - "libgobject-2.0.so.0()(armv7hl)", - "libdbus-1.so.3()(armv7hl)", - "libXi.so.6()(armv7hl)", - "libXcursor.so.1()(armv7hl)", - "libXdamage.so.1()(armv7hl)", - "libXrandr.so.2()(armv7hl)", - "libXcomposite.so.1()(armv7hl)", - "libXext.so.6()(armv7hl)", - "libXfixes.so.3()(armv7hl)", - "libXrender.so.1()(armv7hl)", - "libX11.so.6()(armv7hl)", - "libXss.so.1()(armv7hl)", - "libXtst.so.6()(armv7hl)", - "libgmodule-2.0.so.0()(armv7hl)", - "librt.so.1()(armv7hl)", - "libglib-2.0.so.0()(armv7hl)", - "libnss3.so()(armv7hl)", - "libnssutil3.so()(armv7hl)", - "libsmime3.so()(armv7hl)", - "libnspr4.so()(armv7hl)", - "libasound.so.2()(armv7hl)", - "libcups.so.2()(armv7hl)", - "libdl.so.2()(armv7hl)", - "libexpat.so.1()(armv7hl)", - "libstdc++.so.6()(armv7hl)", - "libstdc++.so.6(GLIBCXX_3.4)(armv7hl)", - "libstdc++.so.6(GLIBCXX_3.4.10)(armv7hl)", - "libstdc++.so.6(GLIBCXX_3.4.11)(armv7hl)", - "libstdc++.so.6(GLIBCXX_3.4.14)(armv7hl)", - "libstdc++.so.6(GLIBCXX_3.4.15)(armv7hl)", - "libstdc++.so.6(GLIBCXX_3.4.9)(armv7hl)", - "libm.so.6()(armv7hl)", - "libm.so.6(GLIBC_2.2.5)(armv7hl)", - "libgcc_s.so.1()(armv7hl)", - "libgcc_s.so.1(GCC_3.0)(armv7hl)", - "libgcc_s.so.1(GCC_4.0.0)(armv7hl)", - "libc.so.6()(armv7hl)", - "libc.so.6(GLIBC_2.11)(armv7hl)", - "libc.so.6(GLIBC_2.2.5)(armv7hl)", - "libc.so.6(GLIBC_2.3)(armv7hl)", - "libc.so.6(GLIBC_2.3.2)(armv7hl)", - "libc.so.6(GLIBC_2.3.4)(armv7hl)", - "libc.so.6(GLIBC_2.4)(armv7hl)", - "libc.so.6(GLIBC_2.6)(armv7hl)", - "libc.so.6(GLIBC_2.7)(armv7hl)", - "libc.so.6(GLIBC_2.9)(armv7hl)", - "libxcb.so.1()(armv7hl)", - "libxkbfile.so.1()(armv7hl)", - "libsecret-1.so.0()(armv7hl)" + "libpthread.so.0()", + "libpthread.so.0(GLIBC_2.2.5)", + "libpthread.so.0(GLIBC_2.3.2)", + "libpthread.so.0(GLIBC_2.3.3)", + "libgtk-3.so.0()", + "libgdk-x11-2.0.so.0()", + "libatk-1.0.so.0()", + "libgio-2.0.so.0()", + "libpangocairo-1.0.so.0()", + "libgdk_pixbuf-2.0.so.0()", + "libcairo.so.2()", + "libpango-1.0.so.0()", + "libfreetype.so.6()", + "libfontconfig.so.1()", + "libgobject-2.0.so.0()", + "libdbus-1.so.3()", + "libXi.so.6()", + "libXcursor.so.1()", + "libXdamage.so.1()", + "libXrandr.so.2()", + "libXcomposite.so.1()", + "libXext.so.6()", + "libXfixes.so.3()", + "libXrender.so.1()", + "libX11.so.6()", + "libXss.so.1()", + "libXtst.so.6()", + "libgmodule-2.0.so.0()", + "librt.so.1()", + "libglib-2.0.so.0()", + "libnss3.so()", + "libnssutil3.so()", + "libsmime3.so()", + "libnspr4.so()", + "libasound.so.2()", + "libcups.so.2()", + "libdl.so.2()", + "libexpat.so.1()", + "libstdc++.so.6()", + "libstdc++.so.6(GLIBCXX_3.4)", + "libstdc++.so.6(GLIBCXX_3.4.10)", + "libstdc++.so.6(GLIBCXX_3.4.11)", + "libstdc++.so.6(GLIBCXX_3.4.14)", + "libstdc++.so.6(GLIBCXX_3.4.15)", + "libstdc++.so.6(GLIBCXX_3.4.9)", + "libm.so.6()", + "libm.so.6(GLIBC_2.2.5)", + "libgcc_s.so.1()", + "libgcc_s.so.1(GCC_3.0)", + "libgcc_s.so.1(GCC_4.0.0)", + "libc.so.6()", + "libc.so.6(GLIBC_2.11)", + "libc.so.6(GLIBC_2.2.5)", + "libc.so.6(GLIBC_2.3)", + "libc.so.6(GLIBC_2.3.2)", + "libc.so.6(GLIBC_2.3.4)", + "libc.so.6(GLIBC_2.4)", + "libc.so.6(GLIBC_2.6)", + "libc.so.6(GLIBC_2.7)", + "libc.so.6(GLIBC_2.9)", + "libxcb.so.1()", + "libxkbfile.so.1()", + "libsecret-1.so.0()" ] } diff --git a/src/bootstrap-fork.js b/src/bootstrap-fork.js index 0cd75027286..68e2219bad8 100644 --- a/src/bootstrap-fork.js +++ b/src/bootstrap-fork.js @@ -13,7 +13,7 @@ const bootstrapNode = require('./bootstrap-node'); bootstrapNode.removeGlobalNodeModuleLookupPaths(); // Enable ASAR in our forked processes -bootstrap.enableASARSupport(); +bootstrap.enableASARSupport(undefined); if (process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']) { bootstrapNode.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']); diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 8036d457adf..fcd68b1f309 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -57,17 +57,15 @@ developerToolsUnbind = registerDeveloperKeybindings(options && options.disallowReloadKeybinding); } - // Enable ASAR support (TODO@sandbox non-sandboxed only) - if (!sandbox) { - globalThis.MonacoBootstrap.enableASARSupport(configuration.appRoot); - } + // Enable ASAR support + globalThis.MonacoBootstrap.enableASARSupport(configuration.appRoot); if (options && typeof options.canModifyDOM === 'function') { options.canModifyDOM(configuration); } - // Get the nls configuration into the process.env as early as possible (TODO@sandbox non-sandboxed only) - const nlsConfig = sandbox ? { availableLanguages: {} } : globalThis.MonacoBootstrap.setupNLS(); + // Get the nls configuration into the process.env as early as possible + const nlsConfig = globalThis.MonacoBootstrap.setupNLS(); let locale = nlsConfig.availableLanguages['*'] || 'en'; if (locale === 'zh-tw') { diff --git a/src/bootstrap.js b/src/bootstrap.js index 4ec4c258967..250ac23b987 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -45,8 +45,8 @@ * @param {string | undefined} appRoot */ function enableASARSupport(appRoot) { - if (!path || !Module) { - console.warn('enableASARSupport() is only available in node.js environments'); + if (!path || !Module || typeof process === 'undefined') { + console.warn('enableASARSupport() is only available in node.js environments'); // TODO@sandbox ASAR is currently non-sandboxed only return; } @@ -127,9 +127,9 @@ * @returns {{locale?: string, availableLanguages: {[lang: string]: string;}, pseudo?: boolean } | undefined} */ function setupNLS() { - if (!path || !fs) { + if (!path || !fs || typeof process === 'undefined') { console.warn('setupNLS() is only available in node.js environments'); - return; + return { availableLanguages: {} }; // TODO@sandbox NLS is currently non-sandboxed only } // Get the nls configuration into the process.env as early as possible. @@ -180,18 +180,21 @@ //#region Portable helpers /** - * @param {{ portable: string; applicationName: string; }} product + * @param {{ portable: string | undefined; applicationName: string; }} product * @returns {{ portableDataPath: string; isPortable: boolean; } | undefined} */ function configurePortable(product) { - if (!path || !fs) { - console.warn('configurePortable() is only available in node.js environments'); + if (!path || !fs || typeof process === 'undefined') { + console.warn('configurePortable() is only available in node.js environments'); // TODO@sandbox Portable is currently non-sandboxed only return; } const appRoot = path.dirname(__dirname); - function getApplicationPath() { + /** + * @param {import('path')} path + */ + function getApplicationPath(path) { if (process.env['VSCODE_DEV']) { return appRoot; } @@ -203,21 +206,24 @@ return path.dirname(path.dirname(appRoot)); } - function getPortableDataPath() { + /** + * @param {import('path')} path + */ + function getPortableDataPath(path) { if (process.env['VSCODE_PORTABLE']) { return process.env['VSCODE_PORTABLE']; } if (process.platform === 'win32' || process.platform === 'linux') { - return path.join(getApplicationPath(), 'data'); + return path.join(getApplicationPath(path), 'data'); } // @ts-ignore const portableDataName = product.portable || `${product.applicationName}-portable-data`; - return path.join(path.dirname(getApplicationPath()), portableDataName); + return path.join(path.dirname(getApplicationPath(path)), portableDataName); } - const portableDataPath = getPortableDataPath(); + const portableDataPath = getPortableDataPath(path); const isPortable = !('target' in product) && fs.existsSync(portableDataPath); const portableTempPath = path.join(portableDataPath, 'tmp'); const isTempPortable = isPortable && fs.existsSync(portableTempPath); @@ -261,6 +267,16 @@ global['diagnosticsSource'] = {}; // Prevents diagnostic channel (which patches "require") from initializing entirely } + function safeProcess() { + const globals = (typeof self === 'object' ? self : typeof global === 'object' ? global : {}); + + if (typeof process !== 'undefined') { + return process; // Native environment (non-sandboxed) + } else if (typeof globals.vscode !== 'undefined') { + return globals.vscode.process; // Native environment (sandboxed) + } + } + //#endregion diff --git a/src/cli.js b/src/cli.js index 872cd66733d..c59d5ae2f6d 100644 --- a/src/cli.js +++ b/src/cli.js @@ -16,7 +16,7 @@ bootstrap.avoidMonkeyPatchFromAppInsights(); bootstrap.configurePortable(product); // Enable ASAR support -bootstrap.enableASARSupport(); +bootstrap.enableASARSupport(undefined); // Load CLI through AMD loader require('./bootstrap-amd').load('vs/code/node/cli'); diff --git a/src/main.js b/src/main.js index b75dd6ad33f..699ccb5b1ab 100644 --- a/src/main.js +++ b/src/main.js @@ -28,7 +28,7 @@ app.allowRendererProcessReuse = false; const portable = bootstrap.configurePortable(product); // Enable ASAR support -bootstrap.enableASARSupport(); +bootstrap.enableASARSupport(undefined); // Set userData path before app 'ready' event const args = parseCLIArgs(); diff --git a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf index 4c16209d6a9..7b9d1812e32 100644 Binary files a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf and b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf differ diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 0e1ba77f691..b996d599700 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -98,6 +98,8 @@ export class IconLabel extends Disposable { private descriptionNode: FastLabelNode | HighlightedLabel | undefined; private descriptionNodeFactory: () => FastLabelNode | HighlightedLabel; + private labelContainer: HTMLElement; + private hoverDelegate: IHoverDelegate | undefined = undefined; private readonly customHovers: Map = new Map(); @@ -106,10 +108,10 @@ export class IconLabel extends Disposable { this.domNode = this._register(new FastLabelNode(dom.append(container, dom.$('.monaco-icon-label')))); - const labelContainer = dom.append(this.domNode.element, dom.$('.monaco-icon-label-container')); + this.labelContainer = dom.append(this.domNode.element, dom.$('.monaco-icon-label-container')); - const nameContainer = dom.append(labelContainer, dom.$('span.monaco-icon-name-container')); - this.descriptionContainer = this._register(new FastLabelNode(dom.append(labelContainer, dom.$('span.monaco-icon-description-container')))); + const nameContainer = dom.append(this.labelContainer, dom.$('span.monaco-icon-name-container')); + this.descriptionContainer = this._register(new FastLabelNode(dom.append(this.labelContainer, dom.$('span.monaco-icon-description-container')))); if (options?.supportHighlights) { this.nameNode = new LabelWithHighlights(nameContainer, !!options.supportCodicons); @@ -149,7 +151,7 @@ export class IconLabel extends Disposable { } this.domNode.className = classes.join(' '); - this.setupHover(this.domNode.element, options?.title); + this.setupHover(this.labelContainer, options?.title); this.nameNode.setLabel(label, options); diff --git a/src/vs/base/common/codicons.ts b/src/vs/base/common/codicons.ts index 3c4fffd3b5c..3cf6193de8d 100644 --- a/src/vs/base/common/codicons.ts +++ b/src/vs/base/common/codicons.ts @@ -484,6 +484,9 @@ export namespace Codicon { export const redo = new Codicon('redo', { character: '\\ebb0' }); export const checkAll = new Codicon('check-all', { character: '\\ebb1' }); export const pinnedDirty = new Codicon('pinned-dirty', { character: '\\ebb2' }); + export const passFilled = new Codicon('pass-filled', { character: '\\ebb3' }); + export const circleLargeFilled = new Codicon('circle-large-filled', { character: '\\ebb4' }); + export const circleLargeOutline = new Codicon('circle-large-outline', { character: '\\ebb5' }); } diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index a28fe0e0d41..c03aef236d8 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -54,7 +54,7 @@ if (typeof process !== 'undefined') { // Native environment (non-sandboxed) nodeProcess = process; } else if (typeof _globals.vscode !== 'undefined') { - // Native envionment (sandboxed) + // Native environment (sandboxed) nodeProcess = _globals.vscode.process; } diff --git a/src/vs/base/node/startupPerf.d.ts b/src/vs/base/node/startupPerf.d.ts new file mode 100644 index 00000000000..62be9ef72ac --- /dev/null +++ b/src/vs/base/node/startupPerf.d.ts @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { PerformanceEntry } from 'perf_hooks'; + +/** + * Return all performance entries captured so far and stop startup + * performance recording. + */ +export function consumeAndStop(): PerformanceEntry[]; diff --git a/src/vs/base/node/startupPerf.js b/src/vs/base/node/startupPerf.js new file mode 100644 index 00000000000..2f3e03f1cca --- /dev/null +++ b/src/vs/base/node/startupPerf.js @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +//@ts-check + +function _factory(sharedObj, nodeRequire) { + if (!sharedObj.MonacoStartupPerformanceMarks) { + + const { PerformanceObserver } = nodeRequire('perf_hooks'); + + let startupEntries = []; + + const startupObs = new PerformanceObserver(list => { startupEntries = startupEntries.concat(list.getEntries()); }); + startupObs.observe({ buffered: true, entryTypes: ['mark'] }); + + sharedObj.MonacoStartupPerformanceMarks = { + startupEntries, + dispose() { + startupObs.disconnect(); + startupEntries.length = 0; + delete sharedObj.MonacoStartupPerformanceMarks; + }, + }; + } + + return { + consumeAndStop() { + const entries = sharedObj.startupEntries.slice(0); + sharedObj.MonacoStartupPerformanceMarks.dispose(); + return entries; + } + }; +} + +// This module can be loaded in an amd and commonjs-context. +// Because we want both instances to use the same perf-data +// we store them globally +if (typeof define === 'function') { + // amd + define([], function () { return _factory(global, require.__$__nodeRequire); }); +} else if (typeof module === 'object' && typeof module.exports === 'object') { + // commonjs + module.exports = _factory(global, require); +} diff --git a/src/vs/base/parts/sandbox/electron-browser/preload.js b/src/vs/base/parts/sandbox/electron-browser/preload.js index 702a28ea652..3ee0b2ca853 100644 --- a/src/vs/base/parts/sandbox/electron-browser/preload.js +++ b/src/vs/base/parts/sandbox/electron-browser/preload.js @@ -108,18 +108,13 @@ get type() { return 'renderer'; }, get execPath() { return process.execPath; }, - _resolveEnv: undefined, resolveEnv: /** * @param userEnv {{[key: string]: string}} * @returns {Promise} */ function (userEnv) { - if (!this._resolveEnv) { - this._resolveEnv = resolveEnv(userEnv); - } - - return this._resolveEnv; + return resolveEnv(userEnv); }, getProcessMemoryInfo: @@ -194,6 +189,9 @@ return true; } + /** @type {Promise | undefined} */ + let resolvedEnv = undefined; + /** * If VSCode is not run from a terminal, we should resolve additional * shell specific environment from the OS shell to ensure we are seeing @@ -204,23 +202,27 @@ * @returns {Promise} */ function resolveEnv(userEnv) { + if (!resolvedEnv) { - // Apply `userEnv` directly - Object.assign(process.env, userEnv); + // Apply `userEnv` directly + Object.assign(process.env, userEnv); - // Resolve `shellEnv` from the main side - return new Promise(function (resolve) { - ipcRenderer.once('vscode:acceptShellEnv', function (event, shellEnv) { + // Resolve `shellEnv` from the main side + resolvedEnv = new Promise(function (resolve) { + ipcRenderer.once('vscode:acceptShellEnv', function (event, shellEnv) { - // Assign all keys of the shell environment to our process environment - // But make sure that the user environment wins in the end - Object.assign(process.env, shellEnv, userEnv); + // Assign all keys of the shell environment to our process environment + // But make sure that the user environment wins in the end + Object.assign(process.env, shellEnv, userEnv); - resolve(); + resolve(); + }); + + ipcRenderer.send('vscode:fetchShellEnv'); }); + } - ipcRenderer.send('vscode:fetchShellEnv'); - }); + return resolvedEnv; } //#endregion diff --git a/src/vs/base/parts/sandbox/electron-sandbox/globals.ts b/src/vs/base/parts/sandbox/electron-sandbox/globals.ts index 1116cf2135f..69f3a2a8637 100644 --- a/src/vs/base/parts/sandbox/electron-sandbox/globals.ts +++ b/src/vs/base/parts/sandbox/electron-sandbox/globals.ts @@ -35,9 +35,10 @@ export interface ISandboxNodeProcess extends INodeProcess { readonly execPath: string; /** - * Resolve the true process environment to use. There are different layers of environment - * that will apply: - * - `process.env`: this is the actual environment of the process + * Resolve the true process environment to use and apply it to `process.env`. + * + * There are different layers of environment that will apply: + * - `process.env`: this is the actual environment of the process before this method * - `shellEnv` : if the program was not started from a terminal, we resolve all shell * variables to get the same experience as if the program was started from * a terminal (Linux, macOS) @@ -45,6 +46,9 @@ export interface ISandboxNodeProcess extends INodeProcess { * from a terminal and changed certain variables * * The order of overwrites is `process.env` < `shellEnv` < `userEnv`. + * + * It is critical that every process awaits this method early on startup to get the right + * set of environment in `process.env`. */ resolveEnv(userEnv: IProcessEnvironment): Promise; diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 597c45bad02..5f91f3fd6d7 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -83,7 +83,6 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { EncryptionMainService, IEncryptionMainService } from 'vs/platform/encryption/electron-main/encryptionMainService'; import { ActiveWindowManager } from 'vs/platform/windows/common/windowTracker'; import { IKeyboardLayoutMainService, KeyboardLayoutMainService } from 'vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService'; -import { toErrorMessage } from 'vs/base/common/errorMessage'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { DisplayMainService, IDisplayMainService } from 'vs/platform/display/electron-main/displayMainService'; import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper'; @@ -272,45 +271,45 @@ export class CodeApplication extends Disposable { let replied = false; function acceptShellEnv(env: NodeJS.ProcessEnv): void { - clearTimeout(shellEnvTimeoutWarningHandle); + clearTimeout(shellEnvSlowWarningHandle); + clearTimeout(shellEnvTimeoutErrorHandle); if (!replied) { - webContents.send('vscode:acceptShellEnv', env); replied = true; + + if (!webContents.isDestroyed()) { + webContents.send('vscode:acceptShellEnv', env); + } } } - const shellEnvTimeoutWarningHandle = setTimeout(function () { - window?.sendWhenReady('vscode:showShellEnvTimeoutWarning'); // notify inside window if we have one + // Handle slow shell environment resolve calls: + // - a warning after 3s but continue to resolve + // - an error after 10s and stop trying to resolve + const shellEnvSlowWarningHandle = setTimeout(() => window?.sendWhenReady('vscode:showShellEnvSlowWarning'), 3000); + const shellEnvTimeoutErrorHandle = setTimeout(function () { + window?.sendWhenReady('vscode:showShellEnvTimeoutError'); acceptShellEnv({}); }, 10000); - try { - - // Prefer to use the args and env from the target window - // when resolving the shell env. It is possible that - // a first window was opened from the UI but a second - // from the CLI and that has implications for wether to - // resolve the shell environment or not. - let args: NativeParsedArgs; - let env: NodeJS.ProcessEnv; - if (window?.config) { - args = window.config; - env = { ...process.env, ...window.config.userEnv }; - } else { - args = this.environmentService.args; - env = process.env; - } - - // Resolve shell env - const shellEnv = await resolveShellEnv(this.logService, args, env); - acceptShellEnv(shellEnv); - } catch (error) { - window?.sendWhenReady('vscode:showShellEnvError', toErrorMessage(error)); // notify inside window if we have one - acceptShellEnv({}); - - this.logService.error('Error fetching shell env', error); + // Prefer to use the args and env from the target window + // when resolving the shell env. It is possible that + // a first window was opened from the UI but a second + // from the CLI and that has implications for wether to + // resolve the shell environment or not. + let args: NativeParsedArgs; + let env: NodeJS.ProcessEnv; + if (window?.config) { + args = window.config; + env = { ...process.env, ...window.config.userEnv }; + } else { + args = this.environmentService.args; + env = process.env; } + + // Resolve shell env + const shellEnv = await resolveShellEnv(this.logService, args, env); + acceptShellEnv(shellEnv); }); ipc.on('vscode:toggleDevTools', (event: IpcMainEvent) => event.sender.toggleDevTools()); diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 6019f2d2062..5b0fe508826 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -9,7 +9,7 @@ import * as nls from 'vs/nls'; import * as perf from 'vs/base/common/performance'; import { Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; -import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event, Details } from 'electron'; +import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event, RenderProcessGoneDetails } from 'electron'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -210,7 +210,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { options.tabbingIdentifier = product.nameShort; // this opts in to sierra tabs } - const useCustomTitleStyle = getTitleBarStyle(this.configurationService, this.environmentService, !!config.extensionDevelopmentPath) === 'custom'; + const useCustomTitleStyle = getTitleBarStyle(this.configurationService) === 'custom'; if (useCustomTitleStyle) { options.titleBarStyle = 'hidden'; this.hiddenTitleBarStyle = true; @@ -543,8 +543,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private onWindowError(error: WindowError.UNRESPONSIVE): void; - private onWindowError(error: WindowError.CRASHED, details: Details): void; - private onWindowError(error: WindowError, details?: Details): void { + private onWindowError(error: WindowError.CRASHED, details: RenderProcessGoneDetails): void; + private onWindowError(error: WindowError, details?: RenderProcessGoneDetails): void { this.logService.error(error === WindowError.CRASHED ? `[VS Code]: renderer process crashed (detail: ${details?.reason})` : '[VS Code]: detected unresponsive'); // If we run extension tests from CLI, showing a dialog is not @@ -685,7 +685,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // (for https://github.com/microsoft/vscode/issues/108571) const currentUserEnv = (this.currentConfig ?? this.pendingLoadConfig)?.userEnv; if (currentUserEnv && isLaunchedFromCli(currentUserEnv) && !isLaunchedFromCli(config.userEnv)) { - config.userEnv = currentUserEnv; + config.userEnv = { ...currentUserEnv, ...config.userEnv }; // still allow to override certain environment as passed in } // If this is the first time the window is loaded, we associate the paths @@ -1145,7 +1145,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private getMenuBarVisibility(): MenuBarVisibility { - let menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService, !!this.currentConfig?.extensionDevelopmentPath); + let menuBarVisibility = getMenuBarVisibility(this.configurationService); if (['visible', 'toggle', 'hidden'].indexOf(menuBarVisibility) < 0) { menuBarVisibility = 'default'; } diff --git a/src/vs/code/node/shellEnv.ts b/src/vs/code/node/shellEnv.ts index 79ba3d252fe..29ef8c143b3 100644 --- a/src/vs/code/node/shellEnv.ts +++ b/src/vs/code/node/shellEnv.ts @@ -9,6 +9,7 @@ import { isWindows } from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; /** * We need to get the environment from a user's shell. @@ -56,7 +57,7 @@ export async function resolveShellEnv(logService: ILogService, args: NativeParse let unixShellEnvPromise: Promise | undefined = undefined; -function doResolveUnixShellEnv(logService: ILogService): Promise { +async function doResolveUnixShellEnv(logService: ILogService): Promise { const promise = new Promise((resolve, reject) => { const runAsNode = process.env['ELECTRON_RUN_AS_NODE']; logService.trace('getUnixShellEnvironment#runAsNode', runAsNode); @@ -125,6 +126,11 @@ function doResolveUnixShellEnv(logService: ILogService): Promise ({})); + try { + return await promise; + } catch (error) { + logService.error('getUnixShellEnvironment#error', toErrorMessage(error)); + + return {}; // ignore any errors + } } diff --git a/src/vs/code/test/electron-main/nativeHelpers.test.ts b/src/vs/code/test/electron-main/nativeHelpers.test.ts index 1ce46448038..1e5724a810f 100644 --- a/src/vs/code/test/electron-main/nativeHelpers.test.ts +++ b/src/vs/code/test/electron-main/nativeHelpers.test.ts @@ -30,7 +30,17 @@ suite('Windows Native Helpers', () => { test('vscode-windows-ca-certs', async () => { // @ts-ignore Windows only const windowsCerts = await import('vscode-windows-ca-certs'); + const store = new windowsCerts.Crypt32(); assert.ok(windowsCerts, 'Unable to load vscode-windows-ca-certs dependency.'); + let certCount = 0; + try { + while (store.next()) { + certCount++; + } + } finally { + store.done(); + } + assert(certCount > 0); }); test('vscode-windows-registry', async () => { diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index 8cf68ea56cc..f09d41eb809 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -18,6 +18,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; import * as dom from 'vs/base/browser/dom'; +import { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations'; export interface IViewZoneData { viewZoneId: string; @@ -239,6 +240,7 @@ export class HitTestContext { public readonly layoutInfo: EditorLayoutInfo; public readonly viewDomNode: HTMLElement; public readonly lineHeight: number; + public readonly atomicSoftTabs: boolean; public readonly typicalHalfwidthCharacterWidth: number; public readonly lastRenderData: PointerHandlerLastRenderData; @@ -251,6 +253,7 @@ export class HitTestContext { this.layoutInfo = options.get(EditorOption.layoutInfo); this.viewDomNode = viewHelper.viewDomNode; this.lineHeight = options.get(EditorOption.lineHeight); + this.atomicSoftTabs = options.get(EditorOption.atomicSoftTabs); this.typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; this.lastRenderData = lastRenderData; this._context = context; @@ -1010,6 +1013,17 @@ export class MouseTargetFactory { }; } + private static _snapToSoftTabBoundary(position: Position, viewModel: IViewModel): Position { + const minColumn = viewModel.getLineMinColumn(position.lineNumber); + const lineContent = viewModel.getLineContent(position.lineNumber); + const { tabSize } = viewModel.getTextModelOptions(); + const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - minColumn, tabSize, Direction.Nearest); + if (newPosition !== -1) { + return new Position(position.lineNumber, newPosition + minColumn); + } + return position; + } + private static _doHitTest(ctx: HitTestContext, request: BareHitTestRequest): IHitTestResult { // State of the art (18.10.2012): // The spec says browsers should support document.caretPositionFromPoint, but nobody implemented it (http://dev.w3.org/csswg/cssom-view/) @@ -1028,24 +1042,24 @@ export class MouseTargetFactory { // Thank you browsers for making this so 'easy' :) + let result: IHitTestResult; if (typeof document.caretRangeFromPoint === 'function') { - - return this._doHitTestWithCaretRangeFromPoint(ctx, request); - + result = this._doHitTestWithCaretRangeFromPoint(ctx, request); } else if ((document).caretPositionFromPoint) { - - return this._doHitTestWithCaretPositionFromPoint(ctx, request.pos.toClientCoordinates()); - + result = this._doHitTestWithCaretPositionFromPoint(ctx, request.pos.toClientCoordinates()); } else if ((document.body).createTextRange) { - - return this._doHitTestWithMoveToPoint(ctx, request.pos.toClientCoordinates()); - + result = this._doHitTestWithMoveToPoint(ctx, request.pos.toClientCoordinates()); + } else { + result = { + position: null, + hitTarget: null + }; } - - return { - position: null, - hitTarget: null - }; + // Snap to the nearest soft tab boundary if atomic soft tabs are enabled. + if (result.position && ctx.atomicSoftTabs) { + result.position = this._snapToSoftTabBoundary(result.position, ctx.model); + } + return result; } } @@ -1059,7 +1073,7 @@ export function shadowCaretRangeFromPoint(shadowRoot: ShadowRoot, x: number, y: // Get the last child of the element until its firstChild is a text node // This assumes that the pointer is on the right of the line, out of the tokens // and that we want to get the offset of the last token of the line - while (el && el.firstChild && el.firstChild.nodeType !== el.firstChild.TEXT_NODE) { + while (el && el.firstChild && el.firstChild.nodeType !== el.firstChild.TEXT_NODE && el.lastChild && el.lastChild.firstChild) { el = el.lastChild; } diff --git a/src/vs/editor/browser/services/abstractCodeEditorService.ts b/src/vs/editor/browser/services/abstractCodeEditorService.ts index f48a9cff839..3ebb6454bb8 100644 --- a/src/vs/editor/browser/services/abstractCodeEditorService.ts +++ b/src/vs/editor/browser/services/abstractCodeEditorService.ts @@ -31,6 +31,8 @@ export abstract class AbstractCodeEditorService extends Disposable implements IC private readonly _onDidChangeTransientModelProperty: Emitter = this._register(new Emitter()); public readonly onDidChangeTransientModelProperty: Event = this._onDidChangeTransientModelProperty.event; + protected readonly _onDecorationTypeRegistered: Emitter = this._register(new Emitter()); + public onDecorationTypeRegistered: Event = this._onDecorationTypeRegistered.event; private readonly _codeEditors: { [editorId: string]: ICodeEditor; }; private readonly _diffEditors: { [editorId: string]: IDiffEditor; }; @@ -93,6 +95,7 @@ export abstract class AbstractCodeEditorService extends Disposable implements IC abstract registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void; abstract removeDecorationType(key: string): void; abstract resolveDecorationOptions(decorationTypeKey: string | undefined, writable: boolean): IModelDecorationOptions; + abstract resolveDecorationCSSRules(decorationTypeKey: string): CSSRuleList | null; private readonly _transientWatchers: { [uri: string]: ModelTransientSettingWatcher; } = {}; private readonly _modelProperties = new Map>(); diff --git a/src/vs/editor/browser/services/codeEditorService.ts b/src/vs/editor/browser/services/codeEditorService.ts index 0174886d201..8665de00275 100644 --- a/src/vs/editor/browser/services/codeEditorService.ts +++ b/src/vs/editor/browser/services/codeEditorService.ts @@ -23,6 +23,7 @@ export interface ICodeEditorService { readonly onDiffEditorRemove: Event; readonly onDidChangeTransientModelProperty: Event; + readonly onDecorationTypeRegistered: Event; addCodeEditor(editor: ICodeEditor): void; @@ -41,6 +42,7 @@ export interface ICodeEditorService { registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void; removeDecorationType(key: string): void; resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions; + resolveDecorationCSSRules(decorationTypeKey: string): CSSRuleList | null; setModelProperty(resource: URI, key: string, value: any): void; getModelProperty(resource: URI, key: string): any; diff --git a/src/vs/editor/browser/services/codeEditorServiceImpl.ts b/src/vs/editor/browser/services/codeEditorServiceImpl.ts index 464c1a33d41..c961bfd7956 100644 --- a/src/vs/editor/browser/services/codeEditorServiceImpl.ts +++ b/src/vs/editor/browser/services/codeEditorServiceImpl.ts @@ -21,6 +21,10 @@ export class RefCountedStyleSheet { private readonly _styleSheet: HTMLStyleElement; private _refCount: number; + public get sheet() { + return this._styleSheet.sheet as CSSStyleSheet; + } + constructor(parent: CodeEditorServiceImpl, editorId: string, styleSheet: HTMLStyleElement) { this._parent = parent; this._editorId = editorId; @@ -53,6 +57,10 @@ export class RefCountedStyleSheet { export class GlobalStyleSheet { private readonly _styleSheet: HTMLStyleElement; + public get sheet() { + return this._styleSheet.sheet as CSSStyleSheet; + } + constructor(styleSheet: HTMLStyleElement) { this._styleSheet = styleSheet; } @@ -129,6 +137,7 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { provider = new DecorationSubTypeOptionsProvider(this._themeService, styleSheet, providerArgs); } this._decorationOptionProviders.set(key, provider); + this._onDecorationTypeRegistered.fire(key); } provider.refCount++; } @@ -153,6 +162,14 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { return provider.getOptions(this, writable); } + public resolveDecorationCSSRules(decorationTypeKey: string) { + const provider = this._decorationOptionProviders.get(decorationTypeKey); + if (!provider) { + return null; + } + return provider.resolveDecorationCSSRules(); + } + abstract getActiveCodeEditor(): ICodeEditor | null; abstract openCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; } @@ -160,9 +177,10 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { interface IModelDecorationOptionsProvider extends IDisposable { refCount: number; getOptions(codeEditorService: AbstractCodeEditorService, writable: boolean): IModelDecorationOptions; + resolveDecorationCSSRules(): CSSRuleList; } -class DecorationSubTypeOptionsProvider implements IModelDecorationOptionsProvider { +export class DecorationSubTypeOptionsProvider implements IModelDecorationOptionsProvider { private readonly _styleSheet: GlobalStyleSheet | RefCountedStyleSheet; public refCount: number; @@ -192,6 +210,10 @@ class DecorationSubTypeOptionsProvider implements IModelDecorationOptionsProvide return options; } + public resolveDecorationCSSRules(): CSSRuleList { + return this._styleSheet.sheet.cssRules; + } + public dispose(): void { if (this._beforeContentRules) { this._beforeContentRules.dispose(); @@ -213,7 +235,7 @@ interface ProviderArguments { } -class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider { +export class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider { private readonly _disposables = new DisposableStore(); private readonly _styleSheet: GlobalStyleSheet | RefCountedStyleSheet; @@ -295,6 +317,10 @@ class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider { }; } + public resolveDecorationCSSRules(): CSSRuleList { + return this._styleSheet.sheet.rules; + } + public dispose(): void { this._disposables.dispose(); this._styleSheet.unref(); diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 1be53aad7a3..6001fb4f7c2 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -226,8 +226,7 @@ class MinimapLayout { * Compute a desired `scrollPosition` such that the slider moves by `delta`. */ public getDesiredScrollTopFromDelta(delta: number): number { - const desiredSliderPosition = this.sliderTop + delta; - return Math.round(desiredSliderPosition / this._computedSliderRatio); + return Math.round(this.scrollTop + delta / this._computedSliderRatio); } public getDesiredScrollTopFromTouchLocation(pageY: number): number { @@ -332,8 +331,9 @@ class MinimapLayout { } const endLineNumber = Math.min(lineCount, startLineNumber + minimapLinesFitting - 1); + const sliderTopAligned = (scrollTop / lineHeight - startLineNumber + 1) * minimapLineHeight / pixelRatio; - return new MinimapLayout(scrollTop, scrollHeight, true, computedSliderRatio, sliderTop, sliderHeight, startLineNumber, endLineNumber); + return new MinimapLayout(scrollTop, scrollHeight, true, computedSliderRatio, sliderTopAligned, sliderHeight, startLineNumber, endLineNumber); } } } diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index beb7331a138..e39d4773399 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1027,6 +1027,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (this._triggerEditorCommand(source, handlerId, payload)) { return; } + + this._commandService.executeCommand(handlerId, payload); } private _startComposition(): void { diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 3853ea42eb5..d314ae046a3 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -420,6 +420,11 @@ export interface IEditorOptions { * Defaults to advanced. */ autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full'; + /** + * Emulate selection behaviour of hard tabs when using soft tabs (spaces) for indentation. + * This means selection will snap to indentation boundaries. + */ + atomicSoftTabs?: boolean; /** * Enable format on type. * Defaults to false. @@ -3631,6 +3636,7 @@ export const enum EditorOption { autoIndent, automaticLayout, autoSurround, + atomicSoftTabs, codeLens, codeLensFontFamily, codeLensFontSize, @@ -3859,6 +3865,10 @@ export const EditorOptions = { description: nls.localize('autoSurround', "Controls whether the editor should automatically surround selections when typing quotes or brackets.") } )), + atomicSoftTabs: register(new EditorBooleanOption( + EditorOption.atomicSoftTabs, 'atomicSoftTabs', false, + { description: nls.localize('atomicSoftTabs', "Emulate selection behaviour of hard tabs when using soft tabs (spaces) for indentation. This means selection will snap to indentation boundaries.") } + )), codeLens: register(new EditorBooleanOption( EditorOption.codeLens, 'codeLens', true, { description: nls.localize('codeLens', "Controls whether the editor shows CodeLens.") } diff --git a/src/vs/editor/common/controller/cursorAtomicMoveOperations.ts b/src/vs/editor/common/controller/cursorAtomicMoveOperations.ts new file mode 100644 index 00000000000..4b3a235278f --- /dev/null +++ b/src/vs/editor/common/controller/cursorAtomicMoveOperations.ts @@ -0,0 +1,160 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CharCode } from 'vs/base/common/charCode'; +import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; + +export const enum Direction { + Left, + Right, + Nearest, +} + +export class AtomicTabMoveOperations { + /** + * Get the visible column at the position. If we get to a non-whitespace character first + * or past the end of string then return -1. + * + * **Note** `position` and the return value are 0-based. + */ + public static whitespaceVisibleColumn(lineContent: string, position: number, tabSize: number): [number, number, number] { + const lineLength = lineContent.length; + let visibleColumn = 0; + let prevTabStopPosition = -1; + let prevTabStopVisibleColumn = -1; + for (let i = 0; i < lineLength; i++) { + if (i === position) { + return [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn]; + } + if (visibleColumn % tabSize === 0) { + prevTabStopPosition = i; + prevTabStopVisibleColumn = visibleColumn; + } + const chCode = lineContent.charCodeAt(i); + switch (chCode) { + case CharCode.Space: + visibleColumn += 1; + break; + case CharCode.Tab: + // Skip to the next multiple of tabSize. + visibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize); + break; + default: + return [-1, -1, -1]; + } + } + if (position === lineLength) { + return [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn]; + } + return [-1, -1, -1]; + } + + /** + * Return the position that should result from a move left, right or to the + * nearest tab, if atomic tabs are enabled. Left and right are used for the + * arrow key movements, nearest is used for mouse selection. It returns + * -1 if atomic tabs are not relevant and you should fall back to normal + * behaviour. + * + * **Note**: `position` and the return value are 0-based. + */ + public static atomicPosition(lineContent: string, position: number, tabSize: number, direction: Direction): number { + const lineLength = lineContent.length; + + // Get the 0-based visible column corresponding to the position, or return + // -1 if it is not in the initial whitespace. + const [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn] = AtomicTabMoveOperations.whitespaceVisibleColumn(lineContent, position, tabSize); + + if (visibleColumn === -1) { + return -1; + } + + // Is the output left or right of the current position. The case for nearest + // where it is the same as the current position is handled in the switch. + let left: boolean; + switch (direction) { + case Direction.Left: + left = true; + break; + case Direction.Right: + left = false; + break; + case Direction.Nearest: + // The code below assumes the output position is either left or right + // of the input position. If it is the same, return immediately. + if (visibleColumn % tabSize === 0) { + return position; + } + // Go to the nearest indentation. + left = visibleColumn % tabSize <= (tabSize / 2); + break; + } + + // If going left, we can just use the info about the last tab stop position and + // last tab stop visible column that we computed in the first walk over the whitespace. + if (left) { + if (prevTabStopPosition === -1) { + return -1; + } + // If the direction is left, we need to keep scanning right to ensure + // that targetVisibleColumn + tabSize is before non-whitespace. + // This is so that when we press left at the end of a partial + // indentation it only goes one character. For example ' foo' with + // tabSize 4, should jump from position 6 to position 5, not 4. + let currentVisibleColumn = prevTabStopVisibleColumn; + for (let i = prevTabStopPosition; i < lineLength; ++i) { + if (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) { + // It is a full indentation. + return prevTabStopPosition; + } + + const chCode = lineContent.charCodeAt(i); + switch (chCode) { + case CharCode.Space: + currentVisibleColumn += 1; + break; + case CharCode.Tab: + currentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize); + break; + default: + return -1; + } + } + if (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) { + return prevTabStopPosition; + } + // It must have been a partial indentation. + return -1; + } + + // We are going right. + const targetVisibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize); + + // We can just continue from where whitespaceVisibleColumn got to. + let currentVisibleColumn = visibleColumn; + for (let i = position; i < lineLength; i++) { + if (currentVisibleColumn === targetVisibleColumn) { + return i; + } + + const chCode = lineContent.charCodeAt(i); + switch (chCode) { + case CharCode.Space: + currentVisibleColumn += 1; + break; + case CharCode.Tab: + currentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize); + break; + default: + return -1; + } + } + // This condition handles when the target column is at the end of the line. + if (currentVisibleColumn === targetVisibleColumn) { + return lineLength; + } + return -1; + } +} diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index aa4a3a89f89..4dbc566441f 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -62,6 +62,7 @@ export class CursorConfiguration { public readonly tabSize: number; public readonly indentSize: number; public readonly insertSpaces: boolean; + public readonly atomicSoftTabs: boolean; public readonly pageSize: number; public readonly lineHeight: number; public readonly useTabStops: boolean; @@ -113,6 +114,7 @@ export class CursorConfiguration { this.tabSize = modelOptions.tabSize; this.indentSize = modelOptions.indentSize; this.insertSpaces = modelOptions.insertSpaces; + this.atomicSoftTabs = options.get(EditorOption.atomicSoftTabs); this.lineHeight = options.get(EditorOption.lineHeight); this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2); this.useTabStops = options.get(EditorOption.useTabStops); @@ -554,14 +556,14 @@ export class CursorColumns { } /** - * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns) + * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns) */ public static prevRenderTabStop(column: number, tabSize: number): number { return column - 1 - (column - 1) % tabSize; } /** - * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns) + * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns) */ public static prevIndentTabStop(column: number, indentSize: number): number { return column - 1 - (column - 1) % indentSize; diff --git a/src/vs/editor/common/controller/cursorMoveOperations.ts b/src/vs/editor/common/controller/cursorMoveOperations.ts index 20ca28947b2..a654865f471 100644 --- a/src/vs/editor/common/controller/cursorMoveOperations.ts +++ b/src/vs/editor/common/controller/cursorMoveOperations.ts @@ -8,6 +8,7 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import * as strings from 'vs/base/common/strings'; import { Constants } from 'vs/base/common/uint'; +import { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations'; export class CursorPosition { _cursorPositionBrand: void; @@ -35,8 +36,20 @@ export class MoveOperations { return new Position(lineNumber, column); } + public static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number): Position { + const minColumn = model.getLineMinColumn(lineNumber); + const lineContent = model.getLineContent(lineNumber); + const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - minColumn, tabSize, Direction.Left); + if (newPosition === -1) { + return this.leftPosition(model, lineNumber, column); + } + return new Position(lineNumber, minColumn + newPosition); + } + public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { - const pos = MoveOperations.leftPosition(model, lineNumber, column); + const pos = config.atomicSoftTabs + ? MoveOperations.leftPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize) + : MoveOperations.leftPosition(model, lineNumber, column); return new CursorPosition(pos.lineNumber, pos.column, 0); } @@ -67,8 +80,20 @@ export class MoveOperations { return new Position(lineNumber, column); } + public static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position { + const minColumn = model.getLineMinColumn(lineNumber); + const lineContent = model.getLineContent(lineNumber); + const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - minColumn, tabSize, Direction.Right); + if (newPosition === -1) { + return this.rightPosition(model, lineNumber, column); + } + return new Position(lineNumber, minColumn + newPosition); + } + public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { - const pos = MoveOperations.rightPosition(model, lineNumber, column); + const pos = config.atomicSoftTabs + ? MoveOperations.rightPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize, config.indentSize) + : MoveOperations.rightPosition(model, lineNumber, column); return new CursorPosition(pos.lineNumber, pos.column, 0); } diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 5a74bd1613e..31e7c8b48da 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1387,6 +1387,7 @@ export interface WorkspaceFileEditOptions { recursive?: boolean; copy?: boolean; folder?: boolean; + maxSize?: number; } export interface WorkspaceFileEdit { diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index c8a841bd212..7558e45806a 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -178,117 +178,118 @@ export enum EditorOption { autoIndent = 8, automaticLayout = 9, autoSurround = 10, - codeLens = 11, - codeLensFontFamily = 12, - codeLensFontSize = 13, - colorDecorators = 14, - columnSelection = 15, - comments = 16, - contextmenu = 17, - copyWithSyntaxHighlighting = 18, - cursorBlinking = 19, - cursorSmoothCaretAnimation = 20, - cursorStyle = 21, - cursorSurroundingLines = 22, - cursorSurroundingLinesStyle = 23, - cursorWidth = 24, - disableLayerHinting = 25, - disableMonospaceOptimizations = 26, - dragAndDrop = 27, - emptySelectionClipboard = 28, - extraEditorClassName = 29, - fastScrollSensitivity = 30, - find = 31, - fixedOverflowWidgets = 32, - folding = 33, - foldingStrategy = 34, - foldingHighlight = 35, - unfoldOnClickAfterEndOfLine = 36, - fontFamily = 37, - fontInfo = 38, - fontLigatures = 39, - fontSize = 40, - fontWeight = 41, - formatOnPaste = 42, - formatOnType = 43, - glyphMargin = 44, - gotoLocation = 45, - hideCursorInOverviewRuler = 46, - highlightActiveIndentGuide = 47, - hover = 48, - inDiffEditor = 49, - letterSpacing = 50, - lightbulb = 51, - lineDecorationsWidth = 52, - lineHeight = 53, - lineNumbers = 54, - lineNumbersMinChars = 55, - links = 56, - matchBrackets = 57, - minimap = 58, - mouseStyle = 59, - mouseWheelScrollSensitivity = 60, - mouseWheelZoom = 61, - multiCursorMergeOverlapping = 62, - multiCursorModifier = 63, - multiCursorPaste = 64, - occurrencesHighlight = 65, - overviewRulerBorder = 66, - overviewRulerLanes = 67, - padding = 68, - parameterHints = 69, - peekWidgetDefaultFocus = 70, - definitionLinkOpensInPeek = 71, - quickSuggestions = 72, - quickSuggestionsDelay = 73, - readOnly = 74, - renameOnType = 75, - renderControlCharacters = 76, - renderIndentGuides = 77, - renderFinalNewline = 78, - renderLineHighlight = 79, - renderLineHighlightOnlyWhenFocus = 80, - renderValidationDecorations = 81, - renderWhitespace = 82, - revealHorizontalRightPadding = 83, - roundedSelection = 84, - rulers = 85, - scrollbar = 86, - scrollBeyondLastColumn = 87, - scrollBeyondLastLine = 88, - scrollPredominantAxis = 89, - selectionClipboard = 90, - selectionHighlight = 91, - selectOnLineNumbers = 92, - showFoldingControls = 93, - showUnused = 94, - snippetSuggestions = 95, - smartSelect = 96, - smoothScrolling = 97, - stopRenderingLineAfter = 98, - suggest = 99, - suggestFontSize = 100, - suggestLineHeight = 101, - suggestOnTriggerCharacters = 102, - suggestSelection = 103, - tabCompletion = 104, - tabIndex = 105, - unusualLineTerminators = 106, - useTabStops = 107, - wordSeparators = 108, - wordWrap = 109, - wordWrapBreakAfterCharacters = 110, - wordWrapBreakBeforeCharacters = 111, - wordWrapColumn = 112, - wordWrapMinified = 113, - wrappingIndent = 114, - wrappingStrategy = 115, - showDeprecated = 116, - editorClassName = 117, - pixelRatio = 118, - tabFocusMode = 119, - layoutInfo = 120, - wrappingInfo = 121 + atomicSoftTabs = 11, + codeLens = 12, + codeLensFontFamily = 13, + codeLensFontSize = 14, + colorDecorators = 15, + columnSelection = 16, + comments = 17, + contextmenu = 18, + copyWithSyntaxHighlighting = 19, + cursorBlinking = 20, + cursorSmoothCaretAnimation = 21, + cursorStyle = 22, + cursorSurroundingLines = 23, + cursorSurroundingLinesStyle = 24, + cursorWidth = 25, + disableLayerHinting = 26, + disableMonospaceOptimizations = 27, + dragAndDrop = 28, + emptySelectionClipboard = 29, + extraEditorClassName = 30, + fastScrollSensitivity = 31, + find = 32, + fixedOverflowWidgets = 33, + folding = 34, + foldingStrategy = 35, + foldingHighlight = 36, + unfoldOnClickAfterEndOfLine = 37, + fontFamily = 38, + fontInfo = 39, + fontLigatures = 40, + fontSize = 41, + fontWeight = 42, + formatOnPaste = 43, + formatOnType = 44, + glyphMargin = 45, + gotoLocation = 46, + hideCursorInOverviewRuler = 47, + highlightActiveIndentGuide = 48, + hover = 49, + inDiffEditor = 50, + letterSpacing = 51, + lightbulb = 52, + lineDecorationsWidth = 53, + lineHeight = 54, + lineNumbers = 55, + lineNumbersMinChars = 56, + links = 57, + matchBrackets = 58, + minimap = 59, + mouseStyle = 60, + mouseWheelScrollSensitivity = 61, + mouseWheelZoom = 62, + multiCursorMergeOverlapping = 63, + multiCursorModifier = 64, + multiCursorPaste = 65, + occurrencesHighlight = 66, + overviewRulerBorder = 67, + overviewRulerLanes = 68, + padding = 69, + parameterHints = 70, + peekWidgetDefaultFocus = 71, + definitionLinkOpensInPeek = 72, + quickSuggestions = 73, + quickSuggestionsDelay = 74, + readOnly = 75, + renameOnType = 76, + renderControlCharacters = 77, + renderIndentGuides = 78, + renderFinalNewline = 79, + renderLineHighlight = 80, + renderLineHighlightOnlyWhenFocus = 81, + renderValidationDecorations = 82, + renderWhitespace = 83, + revealHorizontalRightPadding = 84, + roundedSelection = 85, + rulers = 86, + scrollbar = 87, + scrollBeyondLastColumn = 88, + scrollBeyondLastLine = 89, + scrollPredominantAxis = 90, + selectionClipboard = 91, + selectionHighlight = 92, + selectOnLineNumbers = 93, + showFoldingControls = 94, + showUnused = 95, + snippetSuggestions = 96, + smartSelect = 97, + smoothScrolling = 98, + stopRenderingLineAfter = 99, + suggest = 100, + suggestFontSize = 101, + suggestLineHeight = 102, + suggestOnTriggerCharacters = 103, + suggestSelection = 104, + tabCompletion = 105, + tabIndex = 106, + unusualLineTerminators = 107, + useTabStops = 108, + wordSeparators = 109, + wordWrap = 110, + wordWrapBreakAfterCharacters = 111, + wordWrapBreakBeforeCharacters = 112, + wordWrapColumn = 113, + wordWrapMinified = 114, + wrappingIndent = 115, + wrappingStrategy = 116, + showDeprecated = 117, + editorClassName = 118, + pixelRatio = 119, + tabFocusMode = 120, + layoutInfo = 121, + wrappingInfo = 122 } /** diff --git a/src/vs/editor/common/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts index 1b75f0f7c3c..49b43c10eca 100644 --- a/src/vs/editor/common/viewLayout/viewLineRenderer.ts +++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts @@ -127,7 +127,7 @@ export class RenderLineInput { this.containsRTL = containsRTL; this.fauxIndentLength = fauxIndentLength; this.lineTokens = lineTokens; - this.lineDecorations = lineDecorations; + this.lineDecorations = lineDecorations.sort(LineDecoration.compare); this.tabSize = tabSize; this.startVisibleColumn = startVisibleColumn; this.spaceWidth = spaceWidth; diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index 283e8ef31a3..04e8b8aa037 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -47,7 +47,17 @@ function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString { : nls.localize('links.navigate.kb.alt', "alt + click"); if (link.url) { - const hoverMessage = new MarkdownString('', true).appendMarkdown(`[${label}](${link.url.toString()}) (${kb})`); + let nativeLabel = ''; + if (/^command:/i.test(link.url.toString())) { + // Don't show complete command arguments in the native tooltip + const match = link.url.toString().match(/^command:([^?#]+)/); + if (match) { + const commandId = match[1]; + const nativeLabelText = nls.localize('tooltip.explanation', "Execute command {0}", commandId); + nativeLabel = ` "${nativeLabelText}"`; + } + } + const hoverMessage = new MarkdownString('', true).appendMarkdown(`[${label}](${link.url.toString()}${nativeLabel}) (${kb})`); return hoverMessage; } else { return new MarkdownString().appendText(`${label} (${kb})`); diff --git a/src/vs/editor/test/browser/editorTestServices.ts b/src/vs/editor/test/browser/editorTestServices.ts index e9fba5fbb91..55ceb3734a2 100644 --- a/src/vs/editor/test/browser/editorTestServices.ts +++ b/src/vs/editor/test/browser/editorTestServices.ts @@ -22,6 +22,7 @@ export class TestCodeEditorService extends AbstractCodeEditorService { public registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void { } public removeDecorationType(key: string): void { } public resolveDecorationOptions(decorationTypeKey: string, writable: boolean): IModelDecorationOptions { return {}; } + public resolveDecorationCSSRules(decorationTypeKey: string): CSSRuleList | null { return null; } } export class TestCommandService implements ICommandService { diff --git a/src/vs/editor/test/common/controller/cursorAtomicMoveOperations.test.ts b/src/vs/editor/test/common/controller/cursorAtomicMoveOperations.test.ts new file mode 100644 index 00000000000..e9c60b6e3be --- /dev/null +++ b/src/vs/editor/test/common/controller/cursorAtomicMoveOperations.test.ts @@ -0,0 +1,152 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations'; + +suite('Cursor move command test', () => { + + test('Test whitespaceVisibleColumn', () => { + const testCases = [ + { + lineContent: ' ', + tabSize: 4, + expectedPrevTabStopPosition: [-1, 0, 0, 0, 0, 4, 4, 4, 4, -1], + expectedPrevTabStopVisibleColumn: [-1, 0, 0, 0, 0, 4, 4, 4, 4, -1], + expectedVisibleColumn: [0, 1, 2, 3, 4, 5, 6, 7, 8, -1], + }, + { + lineContent: ' ', + tabSize: 4, + expectedPrevTabStopPosition: [-1, 0, 0, -1], + expectedPrevTabStopVisibleColumn: [-1, 0, 0, -1], + expectedVisibleColumn: [0, 1, 2, -1], + }, + { + lineContent: '\t', + tabSize: 4, + expectedPrevTabStopPosition: [-1, 0, -1], + expectedPrevTabStopVisibleColumn: [-1, 0, -1], + expectedVisibleColumn: [0, 4, -1], + }, + { + lineContent: '\t ', + tabSize: 4, + expectedPrevTabStopPosition: [-1, 0, 1, -1], + expectedPrevTabStopVisibleColumn: [-1, 0, 4, -1], + expectedVisibleColumn: [0, 4, 5, -1], + }, + { + lineContent: ' \t\t ', + tabSize: 4, + expectedPrevTabStopPosition: [-1, 0, 0, 2, 3, -1], + expectedPrevTabStopVisibleColumn: [-1, 0, 0, 4, 8, -1], + expectedVisibleColumn: [0, 1, 4, 8, 9, -1], + }, + { + lineContent: ' \tA', + tabSize: 4, + expectedPrevTabStopPosition: [-1, 0, 0, -1, -1], + expectedPrevTabStopVisibleColumn: [-1, 0, 0, -1, -1], + expectedVisibleColumn: [0, 1, 4, -1, -1], + }, + { + lineContent: 'A', + tabSize: 4, + expectedPrevTabStopPosition: [-1, -1, -1], + expectedPrevTabStopVisibleColumn: [-1, -1, -1], + expectedVisibleColumn: [0, -1, -1], + }, + { + lineContent: '', + tabSize: 4, + expectedPrevTabStopPosition: [-1, -1], + expectedPrevTabStopVisibleColumn: [-1, -1], + expectedVisibleColumn: [0, -1], + }, + ]; + + for (const testCase of testCases) { + const maxPosition = testCase.expectedVisibleColumn.length; + for (let position = 0; position < maxPosition; position++) { + const actual = AtomicTabMoveOperations.whitespaceVisibleColumn(testCase.lineContent, position, testCase.tabSize); + const expected = [ + testCase.expectedPrevTabStopPosition[position], + testCase.expectedPrevTabStopVisibleColumn[position], + testCase.expectedVisibleColumn[position] + ]; + assert.deepStrictEqual(actual, expected); + } + } + }); + + test('Test atomicPosition', () => { + const testCases = [ + { + lineContent: ' ', + tabSize: 4, + expectedLeft: [-1, 0, 0, 0, 0, 4, 4, 4, 4, -1], + expectedRight: [4, 4, 4, 4, 8, 8, 8, 8, -1, -1], + expectedNearest: [0, 0, 0, 4, 4, 4, 4, 8, 8, -1], + }, + { + lineContent: ' \t', + tabSize: 4, + expectedLeft: [-1, 0, 0, -1], + expectedRight: [2, 2, -1, -1], + expectedNearest: [0, 0, 2, -1], + }, + { + lineContent: '\t ', + tabSize: 4, + expectedLeft: [-1, 0, -1, -1], + expectedRight: [1, -1, -1, -1], + expectedNearest: [0, 1, -1, -1], + }, + { + lineContent: ' \t ', + tabSize: 4, + expectedLeft: [-1, 0, 0, -1, -1], + expectedRight: [2, 2, -1, -1, -1], + expectedNearest: [0, 0, 2, -1, -1], + }, + { + lineContent: ' A', + tabSize: 4, + expectedLeft: [-1, 0, 0, 0, 0, 4, 4, 4, 4, -1, -1], + expectedRight: [4, 4, 4, 4, 8, 8, 8, 8, -1, -1, -1], + expectedNearest: [0, 0, 0, 4, 4, 4, 4, 8, 8, -1, -1], + }, + { + lineContent: ' foo', + tabSize: 4, + expectedLeft: [-1, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1], + expectedRight: [4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1], + expectedNearest: [0, 0, 0, 4, 4, -1, -1, -1, -1, -1, -1], + }, + ]; + + for (const testCase of testCases) { + for (const { direction, expected } of [ + { + direction: Direction.Left, + expected: testCase.expectedLeft, + }, + { + direction: Direction.Right, + expected: testCase.expectedRight, + }, + { + direction: Direction.Nearest, + expected: testCase.expectedNearest, + }, + ]) { + + const actual = expected.map((_, i) => AtomicTabMoveOperations.atomicPosition(testCase.lineContent, i, testCase.tabSize, direction)); + assert.deepStrictEqual(actual, expected); + } + } + }); +}); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 529e1fe793a..1fffc80353a 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2967,6 +2967,11 @@ declare namespace monaco.editor { * Defaults to advanced. */ autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full'; + /** + * Emulate selection behaviour of hard tabs when using soft tabs (spaces) for indentation. + * This means selection will snap to indentation boundaries. + */ + atomicSoftTabs?: boolean; /** * Enable format on type. * Defaults to false. @@ -3898,117 +3903,118 @@ declare namespace monaco.editor { autoIndent = 8, automaticLayout = 9, autoSurround = 10, - codeLens = 11, - codeLensFontFamily = 12, - codeLensFontSize = 13, - colorDecorators = 14, - columnSelection = 15, - comments = 16, - contextmenu = 17, - copyWithSyntaxHighlighting = 18, - cursorBlinking = 19, - cursorSmoothCaretAnimation = 20, - cursorStyle = 21, - cursorSurroundingLines = 22, - cursorSurroundingLinesStyle = 23, - cursorWidth = 24, - disableLayerHinting = 25, - disableMonospaceOptimizations = 26, - dragAndDrop = 27, - emptySelectionClipboard = 28, - extraEditorClassName = 29, - fastScrollSensitivity = 30, - find = 31, - fixedOverflowWidgets = 32, - folding = 33, - foldingStrategy = 34, - foldingHighlight = 35, - unfoldOnClickAfterEndOfLine = 36, - fontFamily = 37, - fontInfo = 38, - fontLigatures = 39, - fontSize = 40, - fontWeight = 41, - formatOnPaste = 42, - formatOnType = 43, - glyphMargin = 44, - gotoLocation = 45, - hideCursorInOverviewRuler = 46, - highlightActiveIndentGuide = 47, - hover = 48, - inDiffEditor = 49, - letterSpacing = 50, - lightbulb = 51, - lineDecorationsWidth = 52, - lineHeight = 53, - lineNumbers = 54, - lineNumbersMinChars = 55, - links = 56, - matchBrackets = 57, - minimap = 58, - mouseStyle = 59, - mouseWheelScrollSensitivity = 60, - mouseWheelZoom = 61, - multiCursorMergeOverlapping = 62, - multiCursorModifier = 63, - multiCursorPaste = 64, - occurrencesHighlight = 65, - overviewRulerBorder = 66, - overviewRulerLanes = 67, - padding = 68, - parameterHints = 69, - peekWidgetDefaultFocus = 70, - definitionLinkOpensInPeek = 71, - quickSuggestions = 72, - quickSuggestionsDelay = 73, - readOnly = 74, - renameOnType = 75, - renderControlCharacters = 76, - renderIndentGuides = 77, - renderFinalNewline = 78, - renderLineHighlight = 79, - renderLineHighlightOnlyWhenFocus = 80, - renderValidationDecorations = 81, - renderWhitespace = 82, - revealHorizontalRightPadding = 83, - roundedSelection = 84, - rulers = 85, - scrollbar = 86, - scrollBeyondLastColumn = 87, - scrollBeyondLastLine = 88, - scrollPredominantAxis = 89, - selectionClipboard = 90, - selectionHighlight = 91, - selectOnLineNumbers = 92, - showFoldingControls = 93, - showUnused = 94, - snippetSuggestions = 95, - smartSelect = 96, - smoothScrolling = 97, - stopRenderingLineAfter = 98, - suggest = 99, - suggestFontSize = 100, - suggestLineHeight = 101, - suggestOnTriggerCharacters = 102, - suggestSelection = 103, - tabCompletion = 104, - tabIndex = 105, - unusualLineTerminators = 106, - useTabStops = 107, - wordSeparators = 108, - wordWrap = 109, - wordWrapBreakAfterCharacters = 110, - wordWrapBreakBeforeCharacters = 111, - wordWrapColumn = 112, - wordWrapMinified = 113, - wrappingIndent = 114, - wrappingStrategy = 115, - showDeprecated = 116, - editorClassName = 117, - pixelRatio = 118, - tabFocusMode = 119, - layoutInfo = 120, - wrappingInfo = 121 + atomicSoftTabs = 11, + codeLens = 12, + codeLensFontFamily = 13, + codeLensFontSize = 14, + colorDecorators = 15, + columnSelection = 16, + comments = 17, + contextmenu = 18, + copyWithSyntaxHighlighting = 19, + cursorBlinking = 20, + cursorSmoothCaretAnimation = 21, + cursorStyle = 22, + cursorSurroundingLines = 23, + cursorSurroundingLinesStyle = 24, + cursorWidth = 25, + disableLayerHinting = 26, + disableMonospaceOptimizations = 27, + dragAndDrop = 28, + emptySelectionClipboard = 29, + extraEditorClassName = 30, + fastScrollSensitivity = 31, + find = 32, + fixedOverflowWidgets = 33, + folding = 34, + foldingStrategy = 35, + foldingHighlight = 36, + unfoldOnClickAfterEndOfLine = 37, + fontFamily = 38, + fontInfo = 39, + fontLigatures = 40, + fontSize = 41, + fontWeight = 42, + formatOnPaste = 43, + formatOnType = 44, + glyphMargin = 45, + gotoLocation = 46, + hideCursorInOverviewRuler = 47, + highlightActiveIndentGuide = 48, + hover = 49, + inDiffEditor = 50, + letterSpacing = 51, + lightbulb = 52, + lineDecorationsWidth = 53, + lineHeight = 54, + lineNumbers = 55, + lineNumbersMinChars = 56, + links = 57, + matchBrackets = 58, + minimap = 59, + mouseStyle = 60, + mouseWheelScrollSensitivity = 61, + mouseWheelZoom = 62, + multiCursorMergeOverlapping = 63, + multiCursorModifier = 64, + multiCursorPaste = 65, + occurrencesHighlight = 66, + overviewRulerBorder = 67, + overviewRulerLanes = 68, + padding = 69, + parameterHints = 70, + peekWidgetDefaultFocus = 71, + definitionLinkOpensInPeek = 72, + quickSuggestions = 73, + quickSuggestionsDelay = 74, + readOnly = 75, + renameOnType = 76, + renderControlCharacters = 77, + renderIndentGuides = 78, + renderFinalNewline = 79, + renderLineHighlight = 80, + renderLineHighlightOnlyWhenFocus = 81, + renderValidationDecorations = 82, + renderWhitespace = 83, + revealHorizontalRightPadding = 84, + roundedSelection = 85, + rulers = 86, + scrollbar = 87, + scrollBeyondLastColumn = 88, + scrollBeyondLastLine = 89, + scrollPredominantAxis = 90, + selectionClipboard = 91, + selectionHighlight = 92, + selectOnLineNumbers = 93, + showFoldingControls = 94, + showUnused = 95, + snippetSuggestions = 96, + smartSelect = 97, + smoothScrolling = 98, + stopRenderingLineAfter = 99, + suggest = 100, + suggestFontSize = 101, + suggestLineHeight = 102, + suggestOnTriggerCharacters = 103, + suggestSelection = 104, + tabCompletion = 105, + tabIndex = 106, + unusualLineTerminators = 107, + useTabStops = 108, + wordSeparators = 109, + wordWrap = 110, + wordWrapBreakAfterCharacters = 111, + wordWrapBreakBeforeCharacters = 112, + wordWrapColumn = 113, + wordWrapMinified = 114, + wrappingIndent = 115, + wrappingStrategy = 116, + showDeprecated = 117, + editorClassName = 118, + pixelRatio = 119, + tabFocusMode = 120, + layoutInfo = 121, + wrappingInfo = 122 } export const EditorOptions: { acceptSuggestionOnCommitCharacter: IEditorOption; @@ -4022,6 +4028,7 @@ declare namespace monaco.editor { autoIndent: IEditorOption; automaticLayout: IEditorOption; autoSurround: IEditorOption; + atomicSoftTabs: IEditorOption; codeLens: IEditorOption; codeLensFontFamily: IEditorOption; codeLensFontSize: IEditorOption; @@ -6262,6 +6269,7 @@ declare namespace monaco.languages { recursive?: boolean; copy?: boolean; folder?: boolean; + maxSize?: number; } export interface WorkspaceFileEdit { diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index aa382fdd58d..c06a3511b3a 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -95,7 +95,7 @@ export class MenuId { static readonly MenubarSwitchGroupMenu = new MenuId('MenubarSwitchGroupMenu'); static readonly MenubarTerminalMenu = new MenuId('MenubarTerminalMenu'); static readonly MenubarViewMenu = new MenuId('MenubarViewMenu'); - static readonly MenubarWebNavigationMenu = new MenuId('MenubarWebNavigationMenu'); + static readonly MenubarHomeMenu = new MenuId('MenubarHomeMenu'); static readonly OpenEditorsContext = new MenuId('OpenEditorsContext'); static readonly ProblemsPanelContext = new MenuId('ProblemsPanelContext'); static readonly SCMChangeContext = new MenuId('SCMChangeContext'); diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index 20e6021ff6d..21320c0d6b8 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -416,6 +416,9 @@ class ScopedContextKeyService extends AbstractContextKeyService { if (domNode) { this._domNode = domNode; + if (this._domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) { + console.error('Element already has context attribute'); + } this._domNode.setAttribute(KEYBINDING_CONTEXT_ATTR, String(this._myContextId)); } } diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 4ecb3725163..e2a0efb0bd5 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { isMacintosh, language } from 'vs/base/common/platform'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; -import { app, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, Event, KeyboardEvent } from 'electron'; +import { app, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, KeyboardEvent } from 'electron'; import { getTitleBarStyle, INativeRunActionInWindowRequest, INativeRunKeybindingInWindowRequest, IWindowOpenable } from 'vs/platform/windows/common/windows'; import { OpenContext } from 'vs/platform/windows/node/window'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -61,7 +61,7 @@ export class Menubar { private keybindings: { [commandId: string]: IMenubarKeybinding }; - private readonly fallbackMenuHandlers: { [id: string]: (menuItem: MenuItem, browserWindow: BrowserWindow | undefined, event: Event) => void } = Object.create(null); + private readonly fallbackMenuHandlers: { [id: string]: (menuItem: MenuItem, browserWindow: BrowserWindow | undefined, event: KeyboardEvent) => void } = Object.create(null); constructor( @IUpdateService private readonly updateService: IUpdateService, @@ -82,7 +82,7 @@ export class Menubar { this.menubarMenus = Object.create(null); this.keybindings = Object.create(null); - if (isMacintosh || getTitleBarStyle(this.configurationService, this.environmentService) === 'native') { + if (isMacintosh || getTitleBarStyle(this.configurationService) === 'native') { this.restoreCachedMenubarData(); } @@ -416,7 +416,7 @@ export class Menubar { private shouldDrawMenu(menuId: string): boolean { // We need to draw an empty menu to override the electron default - if (!isMacintosh && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + if (!isMacintosh && getTitleBarStyle(this.configurationService) === 'custom') { return false; } @@ -638,7 +638,7 @@ export class Menubar { private createMenuItem(label: string, click: () => void, enabled?: boolean, checked?: boolean): MenuItem; private createMenuItem(arg1: string, arg2: any, arg3?: boolean, arg4?: boolean): MenuItem { const label = this.mnemonicLabel(arg1); - const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem: MenuItem & IMenuItemWithKeybinding, win: BrowserWindow, event: Event) => { + const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem: MenuItem & IMenuItemWithKeybinding, win: BrowserWindow, event: KeyboardEvent) => { const userSettingsLabel = menuItem ? menuItem.userSettingsLabel : null; let commandId = arg2; if (Array.isArray(arg2)) { diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 934914f8aaa..e24efa83cf1 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -615,11 +615,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain const window = this.windowById(windowId); if (window) { const contents = window.win.webContents; - if (isMacintosh && window.hasHiddenTitleBarStyle && !window.isFullScreen && !contents.isDevToolsOpened()) { - contents.openDevTools({ mode: 'undocked' }); // due to https://github.com/electron/electron/issues/3647 - } else { - contents.toggleDevTools(); - } + contents.toggleDevTools(); } } diff --git a/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts index faceac2c61e..cf7a8df0f65 100644 --- a/src/vs/platform/theme/common/tokenClassificationRegistry.ts +++ b/src/vs/platform/theme/common/tokenClassificationRegistry.ts @@ -522,7 +522,8 @@ function createDefaultTokenClassificationRegistry(): TokenClassificationRegistry registerTokenType('typeParameter', nls.localize('typeParameter', "Style for type parameters."), [['entity.name.type.parameter']]); registerTokenType('function', nls.localize('function', "Style for functions"), [['entity.name.function'], ['support.function']]); - registerTokenType('member', nls.localize('member', "Style for member"), [['entity.name.function.member'], ['support.function']]); + registerTokenType('member', nls.localize('member', "Style for member functions"), [], 'method', 'Deprecated use `method` instead'); + registerTokenType('method', nls.localize('method', "Style for method (member functions)"), [['entity.name.function.member'], ['support.function']]); registerTokenType('macro', nls.localize('macro', "Style for macros."), [['entity.name.function.preprocessor']]); registerTokenType('variable', nls.localize('variable', "Style for variables."), [['variable.other.readwrite'], ['entity.name.variable']]); diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index ce1033b12d9..2e18cc8cd02 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -56,7 +56,8 @@ export class DarwinUpdateService extends AbstractUpdateService { } protected buildUpdateFeedUrl(quality: string): string | undefined { - const url = createUpdateURL('darwin', quality); + const assetID = process.arch === 'x64' ? 'darwin' : 'darwin-arm64'; + const url = createUpdateURL(assetID, quality); try { electron.autoUpdater.setFeedURL({ url }); } catch (e) { diff --git a/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts b/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts index a019d267e69..ce6233924b0 100644 --- a/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts +++ b/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts @@ -125,7 +125,10 @@ export class WebviewProtocolProvider extends Disposable { } } - private async handleWebviewRequest(request: Electron.Request, callback: any) { + private async handleWebviewRequest( + request: Electron.ProtocolRequest, + callback: (response: string | Electron.ProtocolResponse) => void + ) { try { const uri = URI.parse(request.url); const entry = WebviewProtocolProvider.validWebviewFilePaths.get(uri.path); @@ -144,8 +147,8 @@ export class WebviewProtocolProvider extends Disposable { } private async handleWebviewResourceRequest( - request: Electron.Request, - callback: (stream?: NodeJS.ReadableStream | Electron.StreamProtocolResponse | undefined) => void + request: Electron.ProtocolRequest, + callback: (stream: NodeJS.ReadableStream | Electron.ProtocolResponse) => void ) { try { const uri = URI.parse(request.url); @@ -220,14 +223,14 @@ export class WebviewProtocolProvider extends Disposable { if (result.type === WebviewResourceResponse.Type.AccessDenied) { console.error('Webview: Cannot load resource outside of protocol root'); - return callback({ data: null, statusCode: 401 }); + return callback({ data: undefined, statusCode: 401 }); } } } catch { // noop } - return callback({ data: null, statusCode: 404 }); + return callback({ data: undefined, statusCode: 404 }); } public didLoadResource(requestId: number, content: VSBuffer | undefined) { diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 74b87a5c529..40c952136ec 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { isMacintosh, isLinux, isWeb, IProcessEnvironment } from 'vs/base/common/platform'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -85,8 +84,8 @@ export function isFileToOpen(uriToOpen: IWindowOpenable): uriToOpen is IFileToOp export type MenuBarVisibility = 'default' | 'visible' | 'toggle' | 'hidden' | 'compact'; -export function getMenuBarVisibility(configurationService: IConfigurationService, environment: IEnvironmentService, isExtensionDevelopment = environment.isExtensionDevelopment): MenuBarVisibility { - const titleBarStyle = getTitleBarStyle(configurationService, environment, isExtensionDevelopment); +export function getMenuBarVisibility(configurationService: IConfigurationService): MenuBarVisibility { + const titleBarStyle = getTitleBarStyle(configurationService); const menuBarVisibility = configurationService.getValue('window.menuBarVisibility'); if (titleBarStyle === 'native' && menuBarVisibility === 'compact') { @@ -119,18 +118,13 @@ export interface IWindowSettings { enableExperimentalProxyLoginDialog: boolean; } -export function getTitleBarStyle(configurationService: IConfigurationService, environment: IEnvironmentService, isExtensionDevelopment = environment.isExtensionDevelopment): 'native' | 'custom' { +export function getTitleBarStyle(configurationService: IConfigurationService): 'native' | 'custom' { if (isWeb) { return 'custom'; } const configuration = configurationService.getValue('window'); - const isDev = !environment.isBuilt || isExtensionDevelopment; - if (isMacintosh && isDev) { - return 'native'; // not enabled when developing due to https://github.com/electron/electron/issues/3647 - } - if (configuration) { const useNativeTabs = isMacintosh && configuration.nativeTabs === true; if (useNativeTabs) { diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index cc1d0a1288b..30f5d85c93e 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -7,7 +7,6 @@ import * as fs from 'fs'; import { basename, normalize, join, posix } from 'vs/base/common/path'; import { localize } from 'vs/nls'; import * as arrays from 'vs/base/common/arrays'; -import { mixin } from 'vs/base/common/objects'; import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; @@ -1369,7 +1368,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow { // Build INativeWindowConfiguration from config and options - const configuration: INativeWindowConfiguration = mixin({}, options.cli); // inherit all properties from CLI + const configuration = { ...options.cli } as INativeWindowConfiguration; configuration.appRoot = this.environmentService.appRoot; configuration.machineId = this.machineId; configuration.nodeCachedDataDir = this.environmentService.nodeCachedDataDir; diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ad93c03af92..7de4a986580 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1028,7 +1028,7 @@ declare module 'vscode' { * @param element * @param item Undefined properties of `item` should be set then `item` should be returned. */ - resolveTreeItem?(element: T, item: TreeItem2): TreeItem2 | Thenable; + resolveTreeItem?(item: TreeItem2, element: T): ProviderResult; } export class TreeItem2 extends TreeItem { @@ -2200,7 +2200,7 @@ declare module 'vscode' { * null if a top-level test was added or removed. When fired, the consumer * should check the test item and all its children for changes. */ - readonly onDidChangeTest: Event; + readonly onDidChangeTest: Event; /** * An event the fires when all test providers have signalled that the tests @@ -2219,6 +2219,29 @@ declare module 'vscode' { dispose(): void; } + export interface TestChangeEvent { + /** + * List of all tests that are newly added. + */ + readonly added: ReadonlyArray; + + /** + * List of existing tests that have updated. + */ + readonly updated: ReadonlyArray; + + /** + * List of existing tests that have been removed. + */ + readonly removed: ReadonlyArray; + + /** + * Highest node in the test tree under which changes were made. This can + * be easily plugged into events like the TreeDataProvider update event. + */ + readonly commonChangeAncestor: TestItem | null; + } + /** * Tree of tests returned from the provide methods in the {@link TestProvider}. */ @@ -2336,7 +2359,7 @@ declare module 'vscode' { runnable?: boolean; /** - * Whether this test item can be debugged. + * Whether this test item can be debugged. Defaults to `false` if not provided. */ debuggable?: boolean; diff --git a/src/vs/workbench/api/browser/mainThreadTunnelService.ts b/src/vs/workbench/api/browser/mainThreadTunnelService.ts index 3b91d45d95a..af625d0871d 100644 --- a/src/vs/workbench/api/browser/mainThreadTunnelService.ts +++ b/src/vs/workbench/api/browser/mainThreadTunnelService.ts @@ -6,7 +6,7 @@ import { MainThreadTunnelServiceShape, IExtHostContext, MainContext, ExtHostContext, ExtHostTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol'; import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; -import { IRemoteExplorerService, MakeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { IRemoteExplorerService, makeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { ITunnelProvider, ITunnelService, TunnelOptions } from 'vs/platform/remote/common/tunnel'; import { Disposable } from 'vs/base/common/lifecycle'; import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver'; @@ -64,7 +64,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun return { tunnelRemotePort: tunnel.remoteAddress.port, tunnelRemoteHost: tunnel.remoteAddress.host, - localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : MakeAddress(tunnel.localAddress.host, tunnel.localAddress.port), + localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : makeAddress(tunnel.localAddress.host, tunnel.localAddress.port), tunnelLocalPort: typeof tunnel.localAddress !== 'string' ? tunnel.localAddress.port : undefined, dispose: (silent?: boolean) => { this._proxy.$closeTunnel({ host: tunnel.remoteAddress.host, port: tunnel.remoteAddress.port }, silent); diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index 611a5b121c8..841d2ce349b 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -471,10 +471,9 @@ class ViewsExtensionHandler implements IWorkbenchContribution { ? container.viewOrderDelegate.getOrder(item.group) : undefined; - let icon: string | URI | undefined; + let icon: ThemeIcon | URI | undefined; if (typeof item.icon === 'string') { - const themeIcon = ThemeIcon.fromString(item.icon); - icon = themeIcon ? ThemeIcon.asClassName(themeIcon) : resources.joinPath(extension.description.extensionLocation, item.icon); + icon = ThemeIcon.fromString(item.icon) || resources.joinPath(extension.description.extensionLocation, item.icon); } const initialVisibility = this.convertInitialVisibility(item.visibility); diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index 270f66a8847..02fc32cbffb 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -17,9 +17,9 @@ import { ExtHostTestingResource, ExtHostTestingShape, MainContext, MainThreadTes import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { TestItem } from 'vs/workbench/api/common/extHostTypeConverters'; -import { Disposable } from 'vs/workbench/api/common/extHostTypes'; +import { Disposable, RequiredTestItem } from 'vs/workbench/api/common/extHostTypes'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; -import { AbstractIncrementalTestCollection, EMPTY_TEST_RESULT, IncrementalTestCollectionItem, InternalTestItem, RunTestForProviderRequest, RunTestsResult, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { AbstractIncrementalTestCollection, EMPTY_TEST_RESULT, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, RunTestForProviderRequest, RunTestsResult, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; import type * as vscode from 'vscode'; const getTestSubscriptionKey = (resource: ExtHostTestingResource, uri: URI) => `${resource}:${uri.toString()}`; @@ -178,7 +178,7 @@ export class ExtHostTesting implements ExtHostTestingShape { } } -const keyMap: { [K in keyof Omit, 'children'>]: null } = { +const keyMap: { [K in keyof Omit]: null } = { label: null, location: null, state: null, @@ -215,6 +215,9 @@ export interface OwnedCollectionTestItem extends InternalTestItem { previousEquals: (v: vscode.TestItem) => boolean; } +/** + * @private + */ export class OwnedTestCollection { protected readonly testIdToInternal = new Map(); @@ -378,27 +381,160 @@ export class SingleUseTestCollection implements IDisposable { */ interface MirroredCollectionTestItem extends IncrementalTestCollectionItem { revived: vscode.TestItem; + depth: number; wrapped?: vscode.TestItem; } +class MirroredChangeCollector extends IncrementalChangeCollector { + private readonly added = new Set(); + private readonly updated = new Set(); + private readonly removed = new Set(); + + private readonly alreadyRemoved = new Set(); + + public get isEmpty() { + return this.added.size === 0 && this.removed.size === 0 && this.updated.size === 0; + } + + constructor(private readonly collection: MirroredTestCollection, private readonly emitter: Emitter) { + super(); + } + + /** + * @override + */ + public add(node: MirroredCollectionTestItem): void { + this.added.add(node); + } + + /** + * @override + */ + public update(node: MirroredCollectionTestItem): void { + Object.assign(node.revived, TestItem.to(node.item)); + if (!this.added.has(node)) { + this.updated.add(node); + } + } + + /** + * @override + */ + public remove(node: MirroredCollectionTestItem): void { + if (this.added.has(node)) { + this.added.delete(node); + return; + } + + this.updated.delete(node); + + if (node.parent && this.alreadyRemoved.has(node.parent)) { + this.alreadyRemoved.add(node.id); + return; + } + + this.removed.add(node); + } + + /** + * @override + */ + public getChangeEvent(): vscode.TestChangeEvent { + const { collection, added, updated, removed } = this; + return { + get added() { return [...added].map(collection.getPublicTestItem, collection); }, + get updated() { return [...updated].map(collection.getPublicTestItem, collection); }, + get removed() { return [...removed].map(collection.getPublicTestItem, collection); }, + get commonChangeAncestor() { + let ancestorPath: MirroredCollectionTestItem[] | undefined; + const buildAncestorPath = (node: MirroredCollectionTestItem | undefined) => { + if (!node) { + return undefined; + } + + // add the node and all its parents to the list of ancestors. If + // the node is detached, do not return a path (its parent will + // also have been passed to remove() and be present) + const path: MirroredCollectionTestItem[] = new Array(node.depth + 1); + for (let i = node.depth; i >= 0; i--) { + if (!node) { + return undefined; // detached child + } + + path[node.depth] = node; + node = node.parent ? collection.getMirroredTestDataById(node.parent) : undefined; + } + + return path; + }; + + const addAncestorPath = (node: MirroredCollectionTestItem) => { + // fast path: if the common ancestor is already the root, no more work to do + if (ancestorPath && ancestorPath.length === 0) { + return; + } + + const thisPath = buildAncestorPath(node); + if (!thisPath) { + return; + } + + if (!ancestorPath) { + ancestorPath = thisPath; + return; + } + + // removes node from the path to the ancestor that don't match + // the corresponding node in *this* path. + for (let i = ancestorPath.length - 1; i >= 0; i--) { + if (ancestorPath[i] !== thisPath[i]) { + ancestorPath.pop(); + } + } + }; + + const addParentAncestor = (node: MirroredCollectionTestItem) => { + if (ancestorPath && ancestorPath.length === 0) { + // no-op + } else if (node.parent === null) { + ancestorPath = []; + } else { + const parent = collection.getMirroredTestDataById(node.parent); + if (parent) { + addAncestorPath(parent); + } + } + }; + + for (const node of added) { addParentAncestor(node); } + for (const node of updated) { addAncestorPath(node); } + for (const node of removed) { addParentAncestor(node); } + + const ancestor = ancestorPath && ancestorPath[ancestorPath.length - 1]; + return ancestor ? collection.getPublicTestItem(ancestor) : null; + }, + }; + } + + public complete() { + if (!this.isEmpty) { + this.emitter.fire(this.getChangeEvent()); + } + } +} + /** * Maintains tests in this extension host sent from the main thread. * @private */ export class MirroredTestCollection extends AbstractIncrementalTestCollection { - private changeEmitter = new Emitter(); + private changeEmitter = new Emitter(); /** * Change emitter that fires with the same sematics as `TestObserver.onDidChangeTests`. */ public readonly onDidChangeTests = this.changeEmitter.event; - /** - * Mapping of mirrored test items to their underlying ID. Given here to avoid - * exposing them to extensions. - */ - protected readonly mirroredTestIds = new WeakMap(); - /** * Gets a list of root test items. */ @@ -409,67 +545,102 @@ export class MirroredTestCollection extends AbstractIncrementalTestCollection): vscode.TestItem[] { - return itemIds.map(itemId => { + public getAllAsTestItem(itemIds: Iterable): vscode.TestItem[] { + let output: vscode.TestItem[] = []; + for (const itemId of itemIds) { const item = this.items.get(itemId); - return item && this.createCollectionItemWrapper(item); - }).filter(isDefined); + if (item) { + output.push(this.getPublicTestItem(item)); + } + } + + return output; + } + + /** + * + * If the test ID exists, returns its underlying ID. + */ + public getMirroredTestDataById(itemId: string) { + return this.items.get(itemId); } /** * If the test item is a mirrored test item, returns its underlying ID. */ public getMirroredTestDataByReference(item: vscode.TestItem) { - const itemId = this.mirroredTestIds.get(item); - return itemId ? this.items.get(itemId) : undefined; + const id = getMirroredItemId(item); + return id ? this.items.get(id) : undefined; } /** * @override */ - protected createItem(item: InternalTestItem): MirroredCollectionTestItem { - return { ...item, revived: TestItem.to(item.item), children: new Set() }; + protected createItem(item: InternalTestItem, parent?: MirroredCollectionTestItem): MirroredCollectionTestItem { + return { ...item, revived: TestItem.to(item.item), depth: parent ? parent.depth + 1 : 0, children: new Set() }; } /** * @override */ - protected onChange(item: MirroredCollectionTestItem | null) { - if (item) { - Object.assign(item.revived, TestItem.to(item.item)); - } - - this.changeEmitter.fire(item ? this.createCollectionItemWrapper(item) : null); + protected createChangeCollector() { + return new MirroredChangeCollector(this, this.changeEmitter); } - private createCollectionItemWrapper(item: MirroredCollectionTestItem): vscode.TestItem { + /** + * Gets the public test item instance for the given mirrored record. + */ + public getPublicTestItem(item: MirroredCollectionTestItem): vscode.TestItem { if (!item.wrapped) { - item.wrapped = createMirroredTestItem(item, this); - this.mirroredTestIds.set(item.wrapped, item.id); + item.wrapped = new ExtHostTestItem(item, this); } return item.wrapped; } } -const createMirroredTestItem = (internal: MirroredCollectionTestItem, collection: MirroredTestCollection): vscode.TestItem => { - const obj = {}; - - Object.defineProperty(obj, 'children', { - enumerable: true, - configurable: false, - get: () => collection.getAllAsTestItem([...internal.children]) - }); - - simpleProps.forEach(prop => Object.defineProperty(obj, prop, { - enumerable: true, - configurable: false, - get: () => internal.revived[prop], - })); - - return obj as any; +const getMirroredItemId = (item: vscode.TestItem) => { + return (item as any)[MirroredItemId] as string | undefined; }; +const MirroredItemId = Symbol('MirroredItemId'); + +class ExtHostTestItem implements vscode.TestItem, RequiredTestItem { + readonly #internal: MirroredCollectionTestItem; + readonly #collection: MirroredTestCollection; + + public get label() { return this.#internal.revived.label; } + public get description() { return this.#internal.revived.description; } + public get state() { return this.#internal.revived.state; } + public get location() { return this.#internal.revived.location; } + public get runnable() { return this.#internal.revived.runnable ?? true; } + public get debuggable() { return this.#internal.revived.debuggable ?? false; } + public get children() { + return this.#collection.getAllAsTestItem(this.#internal.children); + } + + get [MirroredItemId]() { return this.#internal.id; } + + constructor(internal: MirroredCollectionTestItem, collection: MirroredTestCollection) { + this.#internal = internal; + this.#collection = collection; + } + + public toJSON() { + const serialized: RequiredTestItem = { + label: this.label, + description: this.description, + state: this.state, + location: this.location, + runnable: this.runnable, + debuggable: this.debuggable, + children: this.children.map(c => (c as ExtHostTestItem).toJSON()), + }; + + return serialized; + } +} + interface IObserverData { observers: number; tests: MirroredTestCollection; diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index dfbc29ebbdc..af3a31890f2 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -379,7 +379,7 @@ class ExtHostTreeView extends Disposable { if (element) { const node = this.nodes.get(element); if (node) { - const resolve = await this.dataProvider.resolveTreeItem(element, node.extensionItem); + const resolve = await this.dataProvider.resolveTreeItem(node.extensionItem, element) ?? node.extensionItem; // Resolvable elements. Currently only tooltip. node.item.tooltip = this.getTooltip(resolve.tooltip); return node.item; diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 1013635962d..8788574ca1b 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2940,4 +2940,15 @@ export class TestState { } } +type AllowedUndefined = 'description' | 'location'; + +/** + * Test item without any optional properties. Only some properties are + * permitted to be undefined, but they must still exist. + */ +export type RequiredTestItem = { + [K in keyof Required]: K extends AllowedUndefined ? vscode.TestItem[K] : Required[K] +}; + + //#endregion diff --git a/src/vs/workbench/api/common/menusExtensionPoint.ts b/src/vs/workbench/api/common/menusExtensionPoint.ts index 21af049d770..32027cbe252 100644 --- a/src/vs/workbench/api/common/menusExtensionPoint.ts +++ b/src/vs/workbench/api/common/menusExtensionPoint.ts @@ -73,19 +73,19 @@ const apiMenus: IAPIMenu[] = [ id: MenuId.DebugToolBar, description: localize('menus.debugToolBar', "The debug toolbar menu") }, - { - key: 'menuBar/webNavigation', - id: MenuId.MenubarWebNavigationMenu, - description: localize('menus.webNavigation', "The top level navigational menu (web only)"), - proposed: true, - supportsSubmenus: false - }, { key: 'menuBar/file', id: MenuId.MenubarFileMenu, description: localize('menus.file', "The top level file menu"), proposed: true }, + { + key: 'menuBar/home', + id: MenuId.MenubarHomeMenu, + description: localize('menus.home', "The home indicator context menu (web only)"), + proposed: true, + supportsSubmenus: false + }, { key: 'scm/title', id: MenuId.SCMTitle, diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 68640c8bcd3..cdd2cdfc3c9 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -21,7 +21,6 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { InEditorZenModeContext, IsCenteredLayoutContext, EditorAreaVisibleContext } from 'vs/workbench/common/editor'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { SideBarVisibleContext } from 'vs/workbench/common/viewlet'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IViewDescriptorService, IViewsService, FocusedViewContext, ViewContainerLocation, IViewDescriptor } from 'vs/workbench/common/views'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -419,14 +418,13 @@ export class ToggleMenuBarAction extends Action { constructor( id: string, label: string, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IEnvironmentService private readonly environmentService: IEnvironmentService + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(id, label); } run(): Promise { - let currentVisibilityValue = getMenuBarVisibility(this.configurationService, this.environmentService); + let currentVisibilityValue = getMenuBarVisibility(this.configurationService); if (typeof currentVisibilityValue !== 'string') { currentVisibilityValue = 'default'; } diff --git a/src/vs/workbench/browser/actions/navigationActions.ts b/src/vs/workbench/browser/actions/navigationActions.ts index 7344a3a29b3..5833c3291dc 100644 --- a/src/vs/workbench/browser/actions/navigationActions.ts +++ b/src/vs/workbench/browser/actions/navigationActions.ts @@ -12,13 +12,10 @@ import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/bro import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { IPanel } from 'vs/workbench/common/panel'; -import { Action2, MenuId, registerAction2, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions, CATEGORIES } from 'vs/workbench/common/actions'; import { Direction } from 'vs/base/browser/ui/grid/grid'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { isAncestor } from 'vs/base/browser/dom'; @@ -275,29 +272,6 @@ export class FocusPreviousPart extends Action { } } -class GoHomeContributor implements IWorkbenchContribution { - - constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService - ) { - const homeIndicator = environmentService.options?.homeIndicator; - if (homeIndicator) { - registerAction2(class extends Action2 { - constructor() { - super({ - id: `workbench.actions.goHome`, - title: nls.localize('goHome', "Go Home"), - menu: { id: MenuId.MenubarWebNavigationMenu } - }); - } - async run(): Promise { - window.location.href = homeIndicator.href; - } - }); - } - } -} - // --- Actions Registration const actionsRegistry = Registry.as(Extensions.WorkbenchActions); @@ -308,6 +282,3 @@ actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateLeftAc actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateRightAction, undefined), 'View: Navigate to the View on the Right', CATEGORIES.View.value); actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusNextPart, { primary: KeyCode.F6 }), 'View: Focus Next Part', CATEGORIES.View.value); actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPreviousPart, { primary: KeyMod.Shift | KeyCode.F6 }), 'View: Focus Previous Part', CATEGORIES.View.value); - -const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(GoHomeContributor, LifecyclePhase.Ready); diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index af930f93da7..460594ee0d0 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -303,7 +303,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this._register(addDisposableListener(this.container, EventType.SCROLL, () => this.container.scrollTop = 0)); // Menubar visibility changes - if ((isWindows || isLinux || isWeb) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + if ((isWindows || isLinux || isWeb) && getTitleBarStyle(this.configurationService) === 'custom') { this._register(this.titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible))); } @@ -345,7 +345,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.workbenchGrid.edgeSnapping = this.state.fullscreen; // Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update - if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + if (getTitleBarStyle(this.configurationService) === 'custom') { // Propagate to grid this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART)); @@ -394,7 +394,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } // Menubar visibility - const newMenubarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService); + const newMenubarVisibility = getMenuBarVisibility(this.configurationService); this.setMenubarVisibility(newMenubarVisibility, !!skipLayout); // Centered Layout @@ -438,7 +438,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } private updateWindowBorder(skipLayout: boolean = false) { - if (isWeb || getTitleBarStyle(this.configurationService, this.environmentService) !== 'custom') { + if (isWeb || getTitleBarStyle(this.configurationService) !== 'custom') { return; } @@ -482,7 +482,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.state.fullscreen = isFullscreen(); // Menubar visibility - this.state.menuBar.visibility = getMenuBarVisibility(this.configurationService, this.environmentService); + this.state.menuBar.visibility = getMenuBarVisibility(this.configurationService); // Activity bar visibility this.state.activityBar.hidden = !this.configurationService.getValue(Settings.ACTIVITYBAR_VISIBLE); @@ -878,7 +878,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi isVisible(part: Parts): boolean { switch (part) { case Parts.TITLEBAR_PART: - if (getTitleBarStyle(this.configurationService, this.environmentService) === 'native') { + if (getTitleBarStyle(this.configurationService) === 'native') { return false; } else if (!this.state.fullscreen && !isWeb) { return true; diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 3e47bb6a681..6dbeb2dd61c 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -10,15 +10,14 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; import { Action, IAction, Separator, SubmenuAction } from 'vs/base/common/actions'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { dispose } from 'vs/base/common/lifecycle'; -import { SyncActionDescriptor, IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IMenuService, MenuId, IMenu, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { Registry } from 'vs/platform/registry/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; -import { CATEGORIES, Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; +import { CATEGORIES } from 'vs/workbench/common/actions'; import { IActivity } from 'vs/workbench/common/activity'; import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; @@ -26,44 +25,31 @@ import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/bro import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { Codicon } from 'vs/base/common/codicons'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; import { getCurrentAuthenticationSessionInfo, IAuthenticationService } from 'vs/workbench/services/authentication/browser/authenticationService'; import { AuthenticationSession } from 'vs/editor/common/modes'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProductService } from 'vs/platform/product/common/productService'; import { AnchorAlignment, AnchorAxisAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { getTitleBarStyle } from 'vs/platform/windows/common/windows'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; export class ViewContainerActivityAction extends ActivityAction { private static readonly preventDoubleClickDelay = 300; - private readonly viewletService: IViewletService; - private readonly layoutService: IWorkbenchLayoutService; - private readonly telemetryService: ITelemetryService; - private readonly configurationService: IConfigurationService; - - private lastRun: number; + private lastRun = 0; constructor( activity: IActivity, - @IViewletService viewletService: IViewletService, - @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, - @ITelemetryService telemetryService: ITelemetryService, - @IConfigurationService configurationService: IConfigurationService + @IViewletService private readonly viewletService: IViewletService, + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @ITelemetryService private readonly telemetryService: ITelemetryService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(activity); - - this.lastRun = 0; - this.viewletService = viewletService; - this.layoutService = layoutService; - this.telemetryService = telemetryService; - this.configurationService = configurationService; } updateActivity(activity: IActivity): void { @@ -105,6 +91,7 @@ export class ViewContainerActivityAction extends ActivityAction { this.logAction('show'); await this.viewletService.openViewlet(this.activity.id, true); + return this.activate(); } @@ -117,21 +104,18 @@ export class ViewContainerActivityAction extends ActivityAction { } } -export const ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts'; +class MenuActivityActionViewItem extends ActivityActionViewItem { -export class AccountsActionViewItem extends ActivityActionViewItem { constructor( + private readonly menuId: MenuId, action: ActivityAction, colors: (theme: IColorTheme) => ICompositeBarColors, @IThemeService themeService: IThemeService, - @IContextMenuService protected contextMenuService: IContextMenuService, - @IMenuService protected menuService: IMenuService, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IAuthenticationService private readonly authenticationService: IAuthenticationService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IStorageService private readonly storageService: IStorageService, - @IProductService private readonly productService: IProductService, - @IConfigurationService private readonly configurationService: IConfigurationService, + @IMenuService protected readonly menuService: IMenuService, + @IContextMenuService protected readonly contextMenuService: IContextMenuService, + @IContextKeyService protected readonly contextKeyService: IContextKeyService, + @IConfigurationService protected readonly configurationService: IConfigurationService, + @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService ) { super(action, { draggable: false, colors, icon: true }, themeService); } @@ -161,12 +145,103 @@ export class AccountsActionViewItem extends ActivityActionViewItem { })); } - private async getActions(accountsMenu: IMenu) { + protected async showContextMenu(e?: MouseEvent): Promise { + const disposables = new DisposableStore(); + + const menu = disposables.add(this.menuService.createMenu(this.menuId, this.contextKeyService)); + const actions = await this.resolveActions(menu, disposables); + + const isUsingCustomMenu = isWeb || (getTitleBarStyle(this.configurationService) !== 'native' && !isMacintosh); // see #40262 + const position = this.configurationService.getValue('workbench.sideBar.location'); + + this.contextMenuService.showContextMenu({ + getAnchor: () => isUsingCustomMenu ? this.container : e || this.container, + anchorAlignment: isUsingCustomMenu ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined, + anchorAxisAlignment: isUsingCustomMenu ? AnchorAxisAlignment.HORIZONTAL : AnchorAxisAlignment.VERTICAL, + getActions: () => actions, + onHide: () => disposables.dispose() + }); + } + + protected async resolveActions(menu: IMenu, disposables: DisposableStore): Promise { + const actions: IAction[] = []; + + disposables.add(createAndFillInActionBarActions(menu, undefined, { primary: [], secondary: actions })); + + return actions; + } +} + +export class HomeActivityActionViewItem extends MenuActivityActionViewItem { + + static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator'; + + constructor( + private readonly goHomeHref: string, + action: ActivityAction, + colors: (theme: IColorTheme) => ICompositeBarColors, + @IThemeService themeService: IThemeService, + @IMenuService menuService: IMenuService, + @IContextMenuService contextMenuService: IContextMenuService, + @IContextKeyService contextKeyService: IContextKeyService, + @IConfigurationService configurationService: IConfigurationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IStorageService private readonly storageService: IStorageService + ) { + super(MenuId.MenubarHomeMenu, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService); + } + + protected async resolveActions(homeMenu: IMenu, disposables: DisposableStore): Promise { + const actions = []; + + // Go Home + actions.push(disposables.add(new Action('goHome', nls.localize('goHome', "Go Home"), undefined, true, async () => window.location.href = this.goHomeHref))); + actions.push(disposables.add(new Separator())); + + // Contributed + const contributedActions = await super.resolveActions(homeMenu, disposables); + actions.push(...contributedActions); + + // Hide + if (contributedActions.length > 0) { + actions.push(disposables.add(new Separator())); + } + actions.push(disposables.add(new Action('hide', nls.localize('hide', "Hide"), undefined, true, async () => { + this.storageService.store(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, false, StorageScope.GLOBAL, StorageTarget.USER); + }))); + + return actions; + } +} + +export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { + + static readonly ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts'; + + constructor( + action: ActivityAction, + colors: (theme: IColorTheme) => ICompositeBarColors, + @IThemeService themeService: IThemeService, + @IContextMenuService contextMenuService: IContextMenuService, + @IMenuService menuService: IMenuService, + @IContextKeyService contextKeyService: IContextKeyService, + @IAuthenticationService private readonly authenticationService: IAuthenticationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IStorageService private readonly storageService: IStorageService, + @IProductService private readonly productService: IProductService, + @IConfigurationService configurationService: IConfigurationService, + ) { + super(MenuId.AccountsContext, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService); + } + + protected async resolveActions(accountsMenu: IMenu, disposables: DisposableStore): Promise { + await super.resolveActions(accountsMenu, disposables); + const otherCommands = accountsMenu.getActions(); const providers = this.authenticationService.getProviderIds(); - const allSessions = providers.map(async id => { + const allSessions = providers.map(async providerId => { try { - const sessions = await this.authenticationService.getSessions(id); + const sessions = await this.authenticationService.getSessions(providerId); const groupedSessions: { [label: string]: AuthenticationSession[] } = {}; sessions.forEach(session => { @@ -177,14 +252,9 @@ export class AccountsActionViewItem extends ActivityActionViewItem { } }); - return { - providerId: id, - sessions: groupedSessions - }; + return { providerId, sessions: groupedSessions }; } catch { - return { - providerId: id - }; + return { providerId }; } }); @@ -196,130 +266,67 @@ export class AccountsActionViewItem extends ActivityActionViewItem { if (sessionInfo.sessions) { Object.keys(sessionInfo.sessions).forEach(accountName => { - const hasEmbedderAccountSession = sessionInfo.sessions[accountName].some(session => session.id === (authenticationSession?.id)); - const manageExtensionsAction = new Action(`configureSessions${accountName}`, nls.localize('manageTrustedExtensions', "Manage Trusted Extensions"), '', true, _ => { + const manageExtensionsAction = disposables.add(new Action(`configureSessions${accountName}`, nls.localize('manageTrustedExtensions', "Manage Trusted Extensions"), '', true, () => { return this.authenticationService.manageTrustedExtensionsForAccount(sessionInfo.providerId, accountName); - }); - const signOutAction = new Action('signOut', nls.localize('signOut', "Sign Out"), '', true, _ => { - return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName); - }); + })); - const actions = [manageExtensionsAction]; + const signOutAction = disposables.add(new Action('signOut', nls.localize('signOut', "Sign Out"), '', true, () => { + return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName); + })); + + const providerSubMenuActions = [manageExtensionsAction]; + + const hasEmbedderAccountSession = sessionInfo.sessions[accountName].some(session => session.id === (authenticationSession?.id)); if (!hasEmbedderAccountSession || authenticationSession?.canSignOut) { - actions.push(signOutAction); + providerSubMenuActions.push(signOutAction); } - const menu = new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, actions); - menus.push(menu); + const providerSubMenu = disposables.add(new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, providerSubMenuActions)); + menus.push(providerSubMenu); }); } else { - const menu = new Action('providerUnavailable', nls.localize('authProviderUnavailable', '{0} is currently unavailable', providerDisplayName)); - menus.push(menu); + const providerUnavailableAction = disposables.add(new Action('providerUnavailable', nls.localize('authProviderUnavailable', '{0} is currently unavailable', providerDisplayName))); + menus.push(providerUnavailableAction); } }); if (menus.length && otherCommands.length) { - menus.push(new Separator()); + menus.push(disposables.add(new Separator())); } otherCommands.forEach((group, i) => { const actions = group[1]; menus = menus.concat(actions); if (i !== otherCommands.length - 1) { - menus.push(new Separator()); + menus.push(disposables.add(new Separator())); } }); if (menus.length) { - menus.push(new Separator()); + menus.push(disposables.add(new Separator())); } - menus.push(new Action('hide', nls.localize('hide', "Hide"), undefined, true, _ => { - this.storageService.store(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.GLOBAL, StorageTarget.USER); - return Promise.resolve(); - })); + menus.push(disposables.add(new Action('hide', nls.localize('hide', "Hide"), undefined, true, async () => { + this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.GLOBAL, StorageTarget.USER); + }))); return menus; } - - private async showContextMenu(e?: MouseEvent): Promise { - const accountsActions: IAction[] = []; - const accountsMenu = this.menuService.createMenu(MenuId.AccountsContext, this.contextKeyService); - const actionsDisposable = createAndFillInActionBarActions(accountsMenu, undefined, { primary: [], secondary: accountsActions }); - const customMenus = isWeb || (getTitleBarStyle(this.configurationService, this.environmentService) !== 'native' && !isMacintosh); // see #40262 - const position = this.configurationService.getValue('workbench.sideBar.location'); - - const actions = await this.getActions(accountsMenu); - this.contextMenuService.showContextMenu({ - getAnchor: () => customMenus ? this.container : e || this.container, - anchorAlignment: customMenus ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined, - anchorAxisAlignment: customMenus ? AnchorAxisAlignment.HORIZONTAL : AnchorAxisAlignment.VERTICAL, - getActions: () => actions, - onHide: () => { - accountsMenu.dispose(); - dispose(actionsDisposable); - } - }); - } } -export class GlobalActivityActionViewItem extends ActivityActionViewItem { +export class GlobalActivityActionViewItem extends MenuActivityActionViewItem { constructor( action: ActivityAction, colors: (theme: IColorTheme) => ICompositeBarColors, @IThemeService themeService: IThemeService, - @IMenuService private readonly menuService: IMenuService, - @IContextMenuService protected readonly contextMenuService: IContextMenuService, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IEnvironmentService private readonly environmentService: IEnvironmentService + @IMenuService menuService: IMenuService, + @IContextMenuService contextMenuService: IContextMenuService, + @IContextKeyService contextKeyService: IContextKeyService, + @IConfigurationService configurationService: IConfigurationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService ) { - super(action, { draggable: false, colors, icon: true }, themeService); - } - - render(container: HTMLElement): void { - super.render(container); - - // Context menus are triggered on mouse down so that an item can be picked - // and executed with releasing the mouse over it - - this._register(DOM.addDisposableListener(this.container, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { - DOM.EventHelper.stop(e, true); - this.showContextMenu(e); - })); - - this._register(DOM.addDisposableListener(this.container, DOM.EventType.KEY_UP, (e: KeyboardEvent) => { - let event = new StandardKeyboardEvent(e); - if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { - DOM.EventHelper.stop(e, true); - this.showContextMenu(); - } - })); - - this._register(DOM.addDisposableListener(this.container, TouchEventType.Tap, (e: GestureEvent) => { - DOM.EventHelper.stop(e, true); - this.showContextMenu(); - })); - } - - private showContextMenu(e?: MouseEvent): void { - const globalActivityActions: IAction[] = []; - const globalActivityMenu = this.menuService.createMenu(MenuId.GlobalActivity, this.contextKeyService); - const actionsDisposable = createAndFillInActionBarActions(globalActivityMenu, undefined, { primary: [], secondary: globalActivityActions }); - const customMenus = isWeb || (getTitleBarStyle(this.configurationService, this.environmentService) !== 'native' && !isMacintosh); // see #40262 - const position = this.configurationService.getValue('workbench.sideBar.location'); - - this.contextMenuService.showContextMenu({ - getAnchor: () => customMenus ? this.container : e || this.container, - anchorAlignment: customMenus ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined, - anchorAxisAlignment: customMenus ? AnchorAxisAlignment.HORIZONTAL : AnchorAxisAlignment.VERTICAL, - getActions: () => globalActivityActions, - onHide: () => { - globalActivityMenu.dispose(); - dispose(actionsDisposable); - } - }); + super(MenuId.GlobalActivity, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService); } } @@ -336,106 +343,62 @@ export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinne } } -class SwitchSideBarViewAction extends Action { +class SwitchSideBarViewAction extends Action2 { constructor( - id: string, - name: string, - @IViewletService private readonly viewletService: IViewletService, - @IActivityBarService private readonly activityBarService: IActivityBarService + desc: Readonly, + private readonly offset: number ) { - super(id, name); + super(desc); } - async run(offset: number): Promise { - const visibleViewletIds = this.activityBarService.getVisibleViewContainerIds(); + async run(accessor: ServicesAccessor): Promise { + const activityBarService = accessor.get(IActivityBarService); + const viewletService = accessor.get(IViewletService); - const activeViewlet = this.viewletService.getActiveViewlet(); + const visibleViewletIds = activityBarService.getVisibleViewContainerIds(); + + const activeViewlet = viewletService.getActiveViewlet(); if (!activeViewlet) { return; } let targetViewletId: string | undefined; for (let i = 0; i < visibleViewletIds.length; i++) { if (visibleViewletIds[i] === activeViewlet.getId()) { - targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + offset) % visibleViewletIds.length]; + targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + this.offset) % visibleViewletIds.length]; break; } } - await this.viewletService.openViewlet(targetViewletId, true); + await viewletService.openViewlet(targetViewletId, true); } } -export class PreviousSideBarViewAction extends SwitchSideBarViewAction { - - static readonly ID = 'workbench.action.previousSideBarView'; - static readonly LABEL = nls.localize('previousSideBarView', 'Previous Side Bar View'); - - constructor( - id: string, - name: string, - @IViewletService viewletService: IViewletService, - @IActivityBarService activityBarService: IActivityBarService - ) { - super(id, name, viewletService, activityBarService); - } - - run(): Promise { - return super.run(-1); - } -} - -export class NextSideBarViewAction extends SwitchSideBarViewAction { - - static readonly ID = 'workbench.action.nextSideBarView'; - static readonly LABEL = nls.localize('nextSideBarView', 'Next Side Bar View'); - - constructor( - id: string, - name: string, - @IViewletService viewletService: IViewletService, - @IActivityBarService activityBarService: IActivityBarService - ) { - super(id, name, viewletService, activityBarService); - } - - run(): Promise { - return super.run(1); - } -} - -export class HomeAction extends Action { - - constructor( - private readonly href: string, - name: string, - icon: Codicon - ) { - super('workbench.action.home', name, icon.classNames); - } - - async run(event: MouseEvent): Promise { - let openInNewWindow = false; - if (isMacintosh) { - openInNewWindow = event.metaKey; - } else { - openInNewWindow = event.ctrlKey; - } - - if (openInNewWindow) { - DOM.windowOpenNoOpener(this.href); - } else { - window.location.href = this.href; +registerAction2( + class PreviousSideBarViewAction extends SwitchSideBarViewAction { + constructor() { + super({ + id: 'workbench.action.previousSideBarView', + title: { value: nls.localize('previousSideBarView', "Previous Side Bar View"), original: 'Previous Side Bar View' }, + category: CATEGORIES.View, + f1: true + }, -1); } } -} +); -export class HomeActionViewItem extends ActionViewItem { - - constructor(action: IAction) { - super(undefined, action, { icon: true, label: false, useEventAsContext: true }); +registerAction2( + class NextSideBarViewAction extends SwitchSideBarViewAction { + constructor() { + super({ + id: 'workbench.action.nextSideBarView', + title: { value: nls.localize('nextSideBarView', "Next Side Bar View"), original: 'Next Side Bar View' }, + category: CATEGORIES.View, + f1: true + }, 1); + } } -} +); registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { const activityBarBackgroundColor = theme.getColor(ACTIVITY_BAR_BACKGROUND); @@ -547,7 +510,3 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) = } } }); - -const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(PreviousSideBarViewAction), 'View: Previous Side Bar View', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(NextSideBarViewAction), 'View: Next Side Bar View', CATEGORIES.View.value); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index c7286d2c661..ef4a9b5caa9 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -8,7 +8,7 @@ import * as nls from 'vs/nls'; import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { GLOBAL_ACTIVITY_ID, IActivity, ACCOUNTS_ACTIVITY_ID } from 'vs/workbench/common/activity'; import { Part } from 'vs/workbench/browser/part'; -import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActionViewItem, HomeAction, HomeActionViewItem, ACCOUNTS_VISIBILITY_PREFERENCE_KEY } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; +import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActivityActionViewItem, HomeActivityActionViewItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -25,7 +25,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions'; import { IViewDescriptorService, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewContainerModel, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views'; import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types'; +import { assertIsDefined } from 'vs/base/common/types'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Schemas } from 'vs/base/common/network'; @@ -44,26 +44,26 @@ import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { CATEGORIES } from 'vs/workbench/common/actions'; interface IPlaceholderViewContainer { - id: string; - name?: string; - iconUrl?: UriComponents; - themeIcon?: ThemeIcon; - views?: { when?: string }[]; + readonly id: string; + readonly name?: string; + readonly iconUrl?: UriComponents; + readonly themeIcon?: ThemeIcon; + readonly views?: { when?: string }[]; } interface IPinnedViewContainer { - id: string; - pinned: boolean; - order?: number; - visible: boolean; + readonly id: string; + readonly pinned: boolean; + readonly order?: number; + readonly visible: boolean; } interface ICachedViewContainer { - id: string; + readonly id: string; name?: string; icon?: URI | ThemeIcon; - pinned: boolean; - order?: number; + readonly pinned: boolean; + readonly order?: number; visible: boolean; views?: { when?: string }[]; } @@ -72,11 +72,11 @@ export class ActivitybarPart extends Part implements IActivityBarService { declare readonly _serviceBrand: undefined; - private static readonly ACTION_HEIGHT = 48; - static readonly PINNED_VIEW_CONTAINERS = 'workbench.activity.pinnedViewlets2'; + private static readonly PINNED_VIEW_CONTAINERS = 'workbench.activity.pinnedViewlets2'; private static readonly PLACEHOLDER_VIEW_CONTAINERS = 'workbench.activity.placeholderViewlets'; - private static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator'; + private static readonly ACTION_HEIGHT = 48; private static readonly ACCOUNTS_ACTION_INDEX = 0; + //#region IView readonly minimumWidth: number = 48; @@ -99,17 +99,17 @@ export class ActivitybarPart extends Part implements IActivityBarService { private globalActivityAction: ActivityAction | undefined; private globalActivityActionBar: ActionBar | undefined; - private readonly globalActivity: ICompositeActivity[] = []; private globalActivitiesContainer: HTMLElement | undefined; + private readonly globalActivity: ICompositeActivity[] = []; private accountsActivityAction: ActivityAction | undefined; - private accountsActivity: ICompositeActivity[] = []; + private readonly accountsActivity: ICompositeActivity[] = []; private readonly compositeActions = new Map(); private readonly viewContainerDisposables = new Map(); - private readonly keyboardNavigationDisposables = new DisposableStore(); + private readonly keyboardNavigationDisposables = this._register(new DisposableStore()); private readonly location = ViewContainerLocation.Sidebar; @@ -127,19 +127,33 @@ export class ActivitybarPart extends Part implements IActivityBarService { ) { super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); - this.migrateFromOldCachedViewContainersValue(); - for (const cachedViewContainer of this.cachedViewContainers) { - if (environmentService.remoteAuthority // In remote window, hide activity bar entries until registered. - || this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer) + if ( + environmentService.remoteAuthority || // In remote window, hide activity bar entries until registered + this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer) ) { cachedViewContainer.visible = false; } } + this.compositeBar = this.createCompositeBar(); + + this.onDidRegisterViewContainers(this.getViewContainers()); + + this.registerListeners(); + } + + private createCompositeBar() { const cachedItems = this.cachedViewContainers - .map(v => ({ id: v.id, name: v.name, visible: v.visible, order: v.order, pinned: v.pinned })); - this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, { + .map(container => ({ + id: container.id, + name: container.name, + visible: container.visible, + order: container.order, + pinned: container.pinned + })); + + return this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, { icon: true, orientation: ActionsOrientation.VERTICAL, preventLoopNavigation: true, @@ -148,8 +162,9 @@ export class ActivitybarPart extends Part implements IActivityBarService { getCompositePinnedAction: (compositeId: string) => this.getCompositeActions(compositeId).pinnedAction, getOnCompositeClickAction: (compositeId: string) => new Action(compositeId, '', '', true, () => this.viewsService.isViewContainerVisible(compositeId) ? Promise.resolve(this.viewsService.closeViewContainer(compositeId)) : this.viewsService.openViewContainer(compositeId)), getContextMenuActions: () => { - const menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService); const actions = []; + + // Home if (this.homeBarContainer) { actions.push(new Action( 'toggleHomeBarAction', @@ -160,22 +175,26 @@ export class ActivitybarPart extends Part implements IActivityBarService { )); } + // Menu + const menuBarVisibility = getMenuBarVisibility(this.configurationService); if (menuBarVisibility === 'compact' || (menuBarVisibility === 'hidden' && isWeb)) { actions.push(this.instantiationService.createInstance(ToggleMenuBarAction, ToggleMenuBarAction.ID, menuBarVisibility === 'compact' ? nls.localize('hideMenu', "Hide Menu") : nls.localize('showMenu', "Show Menu"))); } - const toggleAccountsVisibilityAction = new Action( + // Accounts + actions.push(new Action( 'toggleAccountsVisibility', this.accountsVisibilityPreference ? nls.localize('hideAccounts', "Hide Accounts") : nls.localize('showAccounts', "Show Accounts"), undefined, true, async () => { this.accountsVisibilityPreference = !this.accountsVisibilityPreference; } - ); - - actions.push(toggleAccountsVisibilityAction); + )); actions.push(new Separator()); + // Toggle Sidebar actions.push(this.instantiationService.createInstance(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.getLabel(this.layoutService))); + + // Toggle Activity Bar actions.push(new Action( ToggleActivityBarVisibilityAction.ID, nls.localize('hideActivitBar', "Hide Activity Bar"), @@ -198,19 +217,12 @@ export class ActivitybarPart extends Part implements IActivityBarService { colors: (theme: IColorTheme) => this.getActivitybarItemColors(theme), overflowActionSize: ActivitybarPart.ACTION_HEIGHT })); - - this.onDidRegisterViewContainers(this.getViewContainers()); - this.registerListeners(); - } - - focusActivityBar(): void { - this.compositeBar.focus(); } private getContextMenuActionsForComposite(compositeId: string): Action[] { - const viewContainer = this.viewDescriptorService.getViewContainerById(compositeId)!; - const actions = []; + + const viewContainer = this.viewDescriptorService.getViewContainerById(compositeId)!; const defaultLocation = this.viewDescriptorService.getDefaultViewContainerLocation(viewContainer)!; if (defaultLocation !== this.viewDescriptorService.getViewContainerLocation(viewContainer)) { actions.push(new Action('resetLocationAction', nls.localize('resetLocation', "Reset Location"), undefined, true, async () => { @@ -253,7 +265,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Register for configuration changes this._register(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('window.menuBarVisibility')) { - if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') { + if (getMenuBarVisibility(this.configurationService) === 'compact') { this.installMenubar(); } else { this.uninstallMenubar(); @@ -271,6 +283,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { if (from === this.location) { this.onDidDeregisterViewContainer(container); } + if (to === this.location) { this.onDidRegisterViewContainers([container]); } @@ -300,6 +313,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private onDidViewContainerVisible(id: string): void { const viewContainer = this.getViewContainer(id); if (viewContainer) { + // Update the composite bar by adding this.compositeBar.addComposite(viewContainer); this.compositeBar.activateComposite(viewContainer.id); @@ -307,7 +321,8 @@ export class ActivitybarPart extends Part implements IActivityBarService { if (viewContainer.hideIfEmpty) { const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); if (viewContainerModel.activeViewDescriptors.length === 0) { - this.hideComposite(viewContainer.id); // Update the composite bar by hiding + // Update the composite bar by hiding + this.hideComposite(viewContainer.id); } } } @@ -333,6 +348,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { if (typeof priority !== 'number') { priority = 0; } + const activity: ICompositeActivity = { badge, clazz, priority }; const activityCache = activityId === GLOBAL_ACTIVITY_ID ? this.globalActivity : this.accountsActivity; @@ -381,16 +397,18 @@ export class ActivitybarPart extends Part implements IActivityBarService { private getCumulativeNumberBadge(activityCache: ICompositeActivity[], priority: number): NumberBadge { const numberActivities = activityCache.filter(activity => activity.badge instanceof NumberBadge && activity.priority === priority); - let number = numberActivities.reduce((result, activity) => { return result + (activity.badge).number; }, 0); - let descriptorFn = (): string => { + const number = numberActivities.reduce((result, activity) => { return result + (activity.badge).number; }, 0); + const descriptorFn = (): string => { return numberActivities.reduce((result, activity, index) => { result = result + (activity.badge).getDescription(); if (index < numberActivities.length - 1) { - result = result + '\n'; + result = `${result}\n`; } + return result; }, ''); }; + return new NumberBadge(number, descriptorFn); } @@ -408,11 +426,19 @@ export class ActivitybarPart extends Part implements IActivityBarService { } private installMenubar() { + if (this.menuBar) { + return; // prevent menu bar from installing twice #110720 + } + this.menuBarContainer = document.createElement('div'); this.menuBarContainer.classList.add('menubar'); const content = assertIsDefined(this.content); - content.prepend(this.menuBarContainer); + if (this.homeBarContainer) { + content.insertBefore(this.menuBarContainer, this.homeBarContainer.nextSibling); + } else { + content.prepend(this.menuBarContainer); + } // Menubar: install a custom menu bar depending on configuration this.menuBar = this._register(this.instantiationService.createInstance(CustomMenubarControl)); @@ -436,12 +462,12 @@ export class ActivitybarPart extends Part implements IActivityBarService { codicon = Codicon.code; } - this.createHomeBar(homeIndicator.href, homeIndicator.title, codicon); + this.createHomeBar(homeIndicator.href, codicon); this.onDidChangeHomeBarVisibility(); } // Install menubar if compact - if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') { + if (getMenuBarVisibility(this.configurationService) === 'compact') { this.installMenubar(); } @@ -450,11 +476,11 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Global action bar this.globalActivitiesContainer = document.createElement('div'); - this.globalActivitiesContainer.classList.add('global-activity'); this.content.appendChild(this.globalActivitiesContainer); this.createGlobalActivityActionBar(this.globalActivitiesContainer); + // Keyboard Navigation this.registerKeyboardNavigationListeners(); return this.content; @@ -522,23 +548,19 @@ export class ActivitybarPart extends Part implements IActivityBarService { } })); } - - - } - private createHomeBar(href: string, title: string, icon: Codicon): void { + private createHomeBar(href: string, icon: Codicon): void { this.homeBarContainer = document.createElement('div'); this.homeBarContainer.setAttribute('aria-label', nls.localize('homeIndicator', "Home")); this.homeBarContainer.setAttribute('role', 'toolbar'); this.homeBarContainer.classList.add('home-bar'); this.homeBar = this._register(new ActionBar(this.homeBarContainer, { + actionViewItemProvider: action => this.instantiationService.createInstance(HomeActivityActionViewItem, href, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme)), orientation: ActionsOrientation.VERTICAL, - animated: false, ariaLabel: nls.localize('home', "Home"), - actionViewItemProvider: action => new HomeActionViewItem(action), - allowContextMenu: true, + animated: false, preventLoopNavigation: true, ignoreOrientationForPreviousAndNextKey: true })); @@ -546,35 +568,15 @@ export class ActivitybarPart extends Part implements IActivityBarService { const homeBarIconBadge = document.createElement('div'); homeBarIconBadge.classList.add('home-bar-icon-badge'); this.homeBarContainer.appendChild(homeBarIconBadge); - this.homeBar.push(this._register(this.instantiationService.createInstance(HomeAction, href, title, icon))); + + this.homeBar.push(this._register(new ActivityAction({ + id: 'workbench.actions.home', + name: nls.localize('home', "Home"), + cssClass: icon.classNames + }))); const content = assertIsDefined(this.content); - content.prepend(this.homeBarContainer); - } - - updateStyles(): void { - super.updateStyles(); - - const container = assertIsDefined(this.getContainer()); - const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || ''; - container.style.backgroundColor = background; - - const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || ''; - container.classList.toggle('bordered', !!borderColor); - container.style.borderColor = borderColor ? borderColor : ''; - } - - private getActivitybarItemColors(theme: IColorTheme): ICompositeBarColors { - return { - activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND), - inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND), - activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER), - activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND), - badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), - badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), - dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER), - activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined, - }; + content.appendChild(this.homeBarContainer); } private createGlobalActivityActionBar(container: HTMLElement): void { @@ -585,7 +587,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } if (action.id === 'workbench.actions.accounts') { - return this.instantiationService.createInstance(AccountsActionViewItem, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme)); + return this.instantiationService.createInstance(AccountsActivityActionViewItem, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme)); } throw new Error(`No view item for action '${action.id}'`); @@ -597,18 +599,18 @@ export class ActivitybarPart extends Part implements IActivityBarService { ignoreOrientationForPreviousAndNextKey: true })); - this.globalActivityAction = new ActivityAction({ + this.globalActivityAction = this._register(new ActivityAction({ id: 'workbench.actions.manage', name: nls.localize('manage', "Manage"), cssClass: Codicon.settingsGear.classNames - }); + })); if (this.accountsVisibilityPreference) { - this.accountsActivityAction = new ActivityAction({ + this.accountsActivityAction = this._register(new ActivityAction({ id: 'workbench.actions.accounts', name: nls.localize('accounts', "Accounts"), cssClass: Codicon.account.classNames - }); + })); this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX }); } @@ -622,11 +624,11 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.globalActivityActionBar.pull(ActivitybarPart.ACCOUNTS_ACTION_INDEX); this.accountsActivityAction = undefined; } else { - this.accountsActivityAction = new ActivityAction({ + this.accountsActivityAction = this._register(new ActivityAction({ id: 'workbench.actions.accounts', name: nls.localize('accounts', "Accounts"), cssClass: Codicon.account.classNames - }); + })); this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX }); } } @@ -733,6 +735,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } else if (ThemeIcon.isThemeIcon(icon)) { cssClass = ThemeIcon.asClassName(icon); } + return { id, name, cssClass, iconUrl, keybindingId }; } @@ -804,6 +807,35 @@ export class ActivitybarPart extends Part implements IActivityBarService { .map(v => v.id); } + focusActivityBar(): void { + this.compositeBar.focus(); + } + + updateStyles(): void { + super.updateStyles(); + + const container = assertIsDefined(this.getContainer()); + const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || ''; + container.style.backgroundColor = background; + + const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || ''; + container.classList.toggle('bordered', !!borderColor); + container.style.borderColor = borderColor ? borderColor : ''; + } + + private getActivitybarItemColors(theme: IColorTheme): ICompositeBarColors { + return { + activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND), + inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND), + activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER), + activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND), + badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), + badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), + dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER), + activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined, + }; + } + layout(width: number, height: number): void { if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) { return; @@ -828,6 +860,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private getViewContainer(id: string): ViewContainer | undefined { const viewContainer = this.viewDescriptorService.getViewContainerById(id); + return viewContainer && this.viewDescriptorService.getViewContainerLocation(viewContainer) === this.location ? viewContainer : undefined; } @@ -864,11 +897,11 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.compositeBar.setCompositeBarItems(newCompositeItems); } - if (e.key === ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) { + if (e.key === HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) { this.onDidChangeHomeBarVisibility(); } - if (e.key === ACCOUNTS_VISIBILITY_PREFERENCE_KEY && e.scope === StorageScope.GLOBAL) { + if (e.key === AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY && e.scope === StorageScope.GLOBAL) { this.toggleAccountsActivity(); } } @@ -917,6 +950,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } } } + return this._cachedViewContainers; } @@ -927,6 +961,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { visible, order }))); + this.setPlaceholderViewContainers(cachedViewContainers.map(({ id, icon, name, views }) => ({ id, iconUrl: URI.isUri(icon) ? icon : undefined, @@ -1001,33 +1036,19 @@ export class ActivitybarPart extends Part implements IActivityBarService { } private get homeBarVisibilityPreference(): boolean { - return this.storageService.getBoolean(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, StorageScope.GLOBAL, true); + return this.storageService.getBoolean(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, StorageScope.GLOBAL, true); } private set homeBarVisibilityPreference(value: boolean) { - this.storageService.store(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL, StorageTarget.USER); + this.storageService.store(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL, StorageTarget.USER); } private get accountsVisibilityPreference(): boolean { - return this.storageService.getBoolean(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.GLOBAL, true); + return this.storageService.getBoolean(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.GLOBAL, true); } private set accountsVisibilityPreference(value: boolean) { - this.storageService.store(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.GLOBAL, StorageTarget.USER); - } - - private migrateFromOldCachedViewContainersValue(): void { - const value = this.storageService.get('workbench.activity.pinnedViewlets', StorageScope.GLOBAL); - if (value !== undefined) { - const storedStates: Array = JSON.parse(value); - const cachedViewContainers = storedStates.map(c => { - const serialized: ICachedViewContainer = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, name: undefined, icon: undefined, views: undefined } : c; - serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible; - return serialized; - }); - this.storeCachedViewContainersState(cachedViewContainers); - this.storageService.remove('workbench.activity.pinnedViewlets', StorageScope.GLOBAL); - } + this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.GLOBAL, StorageTarget.USER); } toJSON(): object { diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index 39fa9ebde59..57d6f2a8588 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -9,10 +9,6 @@ margin-bottom: 4px; } -.monaco-workbench .activitybar > .content > .home-bar > .monaco-action-bar .action-item { - margin-bottom: 0; -} - .monaco-workbench .activitybar > .content .composite-bar > .monaco-action-bar .action-item::before, .monaco-workbench .activitybar > .content .composite-bar > .monaco-action-bar .action-item::after { position: absolute; diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css index ced2d815834..4f2d86b17a0 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css @@ -51,10 +51,6 @@ position: relative; width: 100%; height: 48px; - display: flex; - align-items: center; - justify-content: center; - order: -1; } .monaco-workbench .activitybar > .content > .home-bar > .home-bar-icon-badge { @@ -88,10 +84,6 @@ margin-bottom: auto; } -.monaco-workbench .activitybar > .content > .composite-bar-excess { - height: 100%; -} - /** Menu Bar */ .monaco-workbench .activitybar .menubar { diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 5d9e68ebc39..36b37447e55 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -487,8 +487,20 @@ function registerOpenEditorAPICommands(): void { const quickInputService = accessor.get(IQuickInputService); const [resource, id, optionsArg, columnArg] = payload; + let group: IEditorGroup | undefined = undefined; + + if (columnArg === SIDE_GROUP) { + const direction = preferredSideBySideGroupDirection(configurationService); + + let neighbourGroup = editorGroupsService.findGroup({ direction }); + if (!neighbourGroup) { + neighbourGroup = editorGroupsService.addGroup(editorGroupsService.activeGroup, direction); + } + group = neighbourGroup; + } else { + group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, columnArg)) ?? editorGroupsService.activeGroup; + } - const group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, columnArg)) ?? editorGroupsService.activeGroup; const textOptions: ITextEditorOptions = optionsArg ? { ...optionsArg, override: false } : { override: false }; const input = editorService.createEditorInput({ resource: URI.revive(resource) }); diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 1b239b03cdd..4557a2c480f 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -246,7 +246,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan diffEditorConfiguration.diffWordWrap = <'off' | 'on' | 'inherit' | undefined>diffEditorConfiguration.wordWrap; delete diffEditorConfiguration.wordWrap; - objects.mixin(editorConfiguration, diffEditorConfiguration); + Object.assign(editorConfiguration, diffEditorConfiguration); } return editorConfiguration; diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index a0416530459..9cae4d21417 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -67,6 +67,7 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa @IEditorGroupsService protected editorGroupService: IEditorGroupsService ) { super(id, telemetryService, themeService, storageService); + this._instantiationService = instantiationService; this.editorMemento = this.getEditorMemento(editorGroupService, BaseTextEditor.TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY, 100); diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 96d407d0538..27fc613ff4e 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -84,10 +84,6 @@ justify-content: center; } -.monaco-workbench .part.panel > .composite.title > .composite-bar-excess { - width: 100px; -} - .monaco-workbench .part.panel > .composite.title> .panel-switcher-container > .monaco-action-bar { line-height: 27px; /* matches panel titles in settings */ height: 35px; diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 6b539f6d0a5..139b4530057 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -249,7 +249,7 @@ export abstract class MenubarControl extends Disposable { } const hasBeenNotified = this.storageService.getBoolean('menubar/accessibleMenubarNotified', StorageScope.GLOBAL, false); - const usingCustomMenubar = getTitleBarStyle(this.configurationService, this.environmentService) === 'custom'; + const usingCustomMenubar = getTitleBarStyle(this.configurationService) === 'custom'; if (hasBeenNotified || usingCustomMenubar || !this.accessibilityService.isScreenReaderOptimized()) { return; @@ -484,7 +484,7 @@ export class CustomMenubarControl extends MenubarControl { } private get currentMenubarVisibility(): MenuBarVisibility { - return getMenuBarVisibility(this.configurationService, this.environmentService); + return getMenuBarVisibility(this.configurationService); } private get currentDisableMenuBarAltFocus(): boolean { @@ -660,25 +660,7 @@ export class CustomMenubarControl extends MenubarControl { visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, - compactMode: this.currentCompactMenuMode, - getCompactMenuActions: () => { - if (!isWeb) { - return []; // only for web - } - - const webNavigationActions: IAction[] = []; - const webNavigationMenu = this.menuService.createMenu(MenuId.MenubarWebNavigationMenu, this.contextKeyService); - for (const groups of webNavigationMenu.getActions()) { - const [, actions] = groups; - for (const action of actions) { - action.label = mnemonicMenuLabel(this.calculateActionLabel(action)); - webNavigationActions.push(action); - } - } - webNavigationMenu.dispose(); - - return webNavigationActions; - } + compactMode: this.currentCompactMenuMode }; } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 2eae92ccf1f..4783cb52259 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -100,7 +100,7 @@ export class TitlebarPart extends Part implements ITitleService { this.contextMenu = this._register(menuService.createMenu(MenuId.TitleBarContext, contextKeyService)); - this.titleBarStyle = getTitleBarStyle(this.configurationService, this.environmentService); + this.titleBarStyle = getTitleBarStyle(this.configurationService); this.registerListeners(); } @@ -461,13 +461,13 @@ export class TitlebarPart extends Part implements ITitleService { } protected get currentMenubarVisibility(): MenuBarVisibility { - return getMenuBarVisibility(this.configurationService, this.environmentService); + return getMenuBarVisibility(this.configurationService); } updateLayout(dimension: Dimension): void { this.lastLayoutDimensions = dimension; - if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + if (getTitleBarStyle(this.configurationService) === 'custom') { // Only prevent zooming behavior on macOS or when the menubar is not visible if ((!isWeb && isMacintosh) || this.currentMenubarVisibility === 'hidden') { this.title.style.zoom = `${1 / getZoomFactor()}`; diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index a5e4e36b614..92a6459dab8 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -556,9 +556,7 @@ export abstract class ViewPane extends Pane implements IView { this.bodyContainer.classList.add('welcome'); this.viewWelcomeContainer.innerText = ''; - let buttonIndex = 0; - - for (const { content, preconditions } of contents) { + for (const { content, precondition } of contents) { const lines = content.split('\n'); for (let line of lines) { @@ -581,21 +579,15 @@ export abstract class ViewPane extends Pane implements IView { disposables.add(button); disposables.add(attachButtonStyler(button, this.themeService)); - if (preconditions) { - const precondition = preconditions[buttonIndex]; + if (precondition) { + const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition); + updateEnablement(); - if (precondition) { - const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition); - updateEnablement(); - - const keys = new Set(); - precondition.keys().forEach(key => keys.add(key)); - const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys)); - onDidChangeContext(updateEnablement, null, disposables); - } + const keys = new Set(); + precondition.keys().forEach(key => keys.add(key)); + const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys)); + onDidChangeContext(updateEnablement, null, disposables); } - - buttonIndex++; } else { const p = append(this.viewWelcomeContainer, $('p')); diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index 95d534a587e..9205a76de48 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -294,11 +294,7 @@ export interface IViewContentDescriptor { readonly when?: ContextKeyExpression | 'default'; readonly group?: string; readonly order?: number; - - /** - * ordered preconditions for each button in the content - */ - readonly preconditions?: (ContextKeyExpression | undefined)[]; + readonly precondition?: ContextKeyExpression | undefined; } export interface IViewsRegistry { diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts index b2840faac3c..47cfebcb1bf 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts @@ -5,7 +5,7 @@ import { WorkspaceFileEditOptions } from 'vs/editor/common/modes'; -import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; +import { IFileService, FileSystemProviderCapabilities, IFileContent } from 'vs/platform/files/common/files'; import { IProgress } from 'vs/platform/progress/common/progress'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; @@ -163,10 +163,10 @@ class DeleteOperation implements IFileOperation { return new Noop(); } - let contents: VSBuffer | undefined; + let fileContent: IFileContent | undefined; if (!this._undoesCreateOperation && !this.options.folder) { try { - contents = (await this._fileService.readFile(this.oldUri)).value; + fileContent = (await this._fileService.readFile(this.oldUri)); } catch (err) { this._logService.critical(err); } @@ -174,7 +174,11 @@ class DeleteOperation implements IFileOperation { const useTrash = this._fileService.hasCapability(this.oldUri, FileSystemProviderCapabilities.Trash) && this._configurationService.getValue('files.enableTrash'); await this._workingCopyFileService.delete([this.oldUri], { useTrash, recursive: this.options.recursive, ...this.undoRedoInfo }); - return this._instaService.createInstance(CreateOperation, this.oldUri, this.options, { isUndoing: true }, contents); + + if (typeof this.options.maxSize === 'number' && fileContent && (fileContent?.size > this.options.maxSize)) { + return new Noop(); + } + return this._instaService.createInstance(CreateOperation, this.oldUri, this.options, { isUndoing: true }, fileContent?.value); } toString(): string { diff --git a/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts index f2770354531..76ffc0b6094 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts @@ -287,8 +287,7 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant { ? setting : Object.keys(setting).filter(x => setting[x]); - const codeActionsOnSave = settingItems - .map(x => new CodeActionKind(x)); + const codeActionsOnSave = this.createCodeActionsOnSave(settingItems); if (!Array.isArray(setting)) { codeActionsOnSave.sort((a, b) => { @@ -319,6 +318,15 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant { await this.applyOnSaveActions(textEditorModel, codeActionsOnSave, excludedActions, progress, token); } + private createCodeActionsOnSave(settingItems: readonly string[]): CodeActionKind[] { + const kinds = settingItems.map(x => new CodeActionKind(x)); + + // Remove subsets + return kinds.filter(kind => { + return kinds.every(otherKind => otherKind.equals(kind) || !otherKind.contains(kind)); + }); + } + private async applyOnSaveActions(model: ITextModel, codeActionsOnSave: readonly CodeActionKind[], excludes: readonly CodeActionKind[], progress: IProgress, token: CancellationToken): Promise { const getActionProgress = new class implements IProgress { diff --git a/src/vs/workbench/contrib/debug/browser/welcomeView.ts b/src/vs/workbench/contrib/debug/browser/welcomeView.ts index 497a58b24af..c88b28e8b6f 100644 --- a/src/vs/workbench/contrib/debug/browser/welcomeView.ts +++ b/src/vs/workbench/contrib/debug/browser/welcomeView.ts @@ -117,7 +117,6 @@ let debugKeybindingLabel = ''; viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { content: localize({ key: 'runAndDebugAction', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] }, "[Run and Debug{0}](command:{1})", debugKeybindingLabel, StartAction.ID), - preconditions: [CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR], when: CONTEXT_DEBUGGERS_AVAILABLE, group: ViewContentGroups.Debug }); diff --git a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts index 0f0374d541b..c6ffbcf5507 100644 --- a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts @@ -16,7 +16,7 @@ declare module DebugProtocol { /** Message type. Values: 'request', 'response', 'event', etc. */ - type: string; + type: 'request' | 'response' | 'event' | string; } /** A client or debug adapter initiated request. */ @@ -56,7 +56,7 @@ declare module DebugProtocol { 'cancelled': request was cancelled. etc. */ - message?: string; + message?: 'cancelled' | string; /** Contains request result if success is true and optional error details if success is false. */ body?: any; } @@ -129,7 +129,7 @@ declare module DebugProtocol { 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', 'instruction breakpoint', etc. */ - reason: string; + reason: 'step' | 'breakpoint' | 'exception' | 'pause' | 'entry' | 'goto' | 'function breakpoint' | 'data breakpoint' | 'instruction breakpoint' | 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. */ @@ -194,7 +194,7 @@ declare module DebugProtocol { /** The reason for the event. Values: 'started', 'exited', etc. */ - reason: string; + reason: 'started' | 'exited' | string; /** The identifier of the thread. */ threadId: number; }; @@ -209,7 +209,7 @@ declare module DebugProtocol { /** The output category. If not specified, 'console' is assumed. Values: 'console', 'stdout', 'stderr', 'telemetry', etc. */ - category?: string; + category?: 'console' | 'stdout' | 'stderr' | 'telemetry' | string; /** The output to report. */ output: string; /** Support for keeping an output log organized by grouping related messages. @@ -221,7 +221,7 @@ declare module DebugProtocol { A non empty 'output' attribute is shown as the unindented end of the group. */ group?: 'start' | 'startCollapsed' | 'end'; - /** 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). */ + /** 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; @@ -243,7 +243,7 @@ declare module DebugProtocol { /** The reason for the event. Values: 'changed', 'new', 'removed', etc. */ - reason: string; + reason: 'changed' | 'new' | 'removed' | string; /** The 'id' attribute is used to find the target breakpoint and the other attributes are used as the new values. */ breakpoint: Breakpoint; }; @@ -383,7 +383,7 @@ declare module DebugProtocol { export interface InvalidatedEvent extends Event { // event: 'invalidated'; body: { - /** Optional set of logical areas that got invalidated. If this property is missing or empty, a single value 'all' is assumed. */ + /** Optional set of logical areas that got invalidated. This property has a hint characteristic: a client can only be expected to make a 'best effort' in honouring the areas but there are no guarantees. If this property is missing, empty, or if values are not understand the client should assume a single value 'all'. */ areas?: InvalidatedAreas[]; /** If specified, the client only needs to refetch data related to this thread. */ threadId?: number; @@ -408,7 +408,7 @@ declare module DebugProtocol { kind?: 'integrated' | 'external'; /** Optional title of the terminal. */ title?: string; - /** Working directory of the command. */ + /** Working directory for the command. For non-empty, valid paths this typically results in execution of a change directory command. */ cwd: string; /** List of arguments. The first argument is the command to run. */ args: string[]; @@ -419,9 +419,9 @@ declare module DebugProtocol { /** 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). */ + /** 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). */ + /** The process ID of the terminal shell. The value should be less than or equal to 2147483647 (2^31-1). */ shellProcessId?: number; }; } @@ -455,7 +455,7 @@ declare module DebugProtocol { /** Determines in what format paths are specified. The default is 'path', which is the native format. Values: 'path', 'uri', etc. */ - pathFormat?: string; + pathFormat?: 'path' | 'uri' | string; /** Client supports the optional type attribute for variables. */ supportsVariableType?: boolean; /** Client supports the paging of variables. */ @@ -712,8 +712,10 @@ declare module DebugProtocol { /** Arguments for 'setExceptionBreakpoints' request. */ export interface SetExceptionBreakpointsArguments { - /** IDs of checked exception options. The set of IDs is returned via the 'exceptionBreakpointFilters' capability. */ + /** Set of exception filters specified by their ID. The set of all possible exception filters is defined by the 'exceptionBreakpointFilters' capability. */ filters: string[]; + /** Set of exception filters and their options. The set of all possible exception filters is defined by the 'exceptionBreakpointFilters' capability. This attribute is only honored by a debug adapter if the capability 'supportsExceptionFilterOptions' is true. */ + filterOptions?: ExceptionFilterOptions[]; /** Configuration options for selected exceptions. The attribute is only honored by a debug adapter if the capability 'supportsExceptionOptions' is true. */ @@ -1125,17 +1127,17 @@ declare module DebugProtocol { /** 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). + 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). + 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). + The value should be less than or equal to 2147483647 (2^31-1). */ indexedVariables?: number; }; @@ -1275,7 +1277,7 @@ declare module DebugProtocol { The attribute is only honored by a debug adapter if the capability 'supportsClipboardContext' is true. etc. */ - context?: string; + context?: 'watch' | 'repl' | 'hover' | 'clipboard' | string; /** Specifies details on how to format the Evaluate result. The attribute is only honored by a debug adapter if the capability 'supportsValueFormattingOptions' is true. */ @@ -1294,17 +1296,17 @@ declare module DebugProtocol { /** 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). + 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). + 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). + The value should be less than or equal to 2147483647 (2^31-1). */ indexedVariables?: number; /** Optional memory reference to a location appropriate for this result. @@ -1349,17 +1351,17 @@ declare module DebugProtocol { /** 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). + 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). + 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). + The value should be less than or equal to 2147483647 (2^31-1). */ indexedVariables?: number; }; @@ -1556,7 +1558,7 @@ declare module DebugProtocol { 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. */ + /** Available exception filter options for the 'setExceptionBreakpoints' request. */ exceptionBreakpointFilters?: ExceptionBreakpointsFilter[]; /** The debug adapter supports stepping back via the 'stepBack' and 'reverseContinue' requests. */ supportsStepBack?: boolean; @@ -1616,16 +1618,20 @@ declare module DebugProtocol { supportsSteppingGranularity?: boolean; /** The debug adapter supports adding breakpoints based on instruction references. */ supportsInstructionBreakpoints?: boolean; + /** The debug adapter supports 'filterOptions' as an argument on the 'setExceptionBreakpoints' request. */ + supportsExceptionFilterOptions?: boolean; } - /** An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with. */ + /** An ExceptionBreakpointsFilter is shown in the UI as an filter 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. */ + /** The internal ID of the filter option. This value is passed to the 'setExceptionBreakpoints' request. */ filter: string; - /** The name of the filter. This will be shown in the UI. */ + /** The name of the filter option. This will be shown in the UI. */ label: string; - /** Initial value of the filter. If not specified a value 'false' is assumed. */ + /** Initial value of the filter option. If not specified a value 'false' is assumed. */ default?: boolean; + /** Controls whether a condition can be specified for this filter option. If false or missing, a condition can not be set. */ + supportsCondition?: boolean; } /** A structured message object. Used to return errors from requests. */ @@ -1730,7 +1736,7 @@ declare module DebugProtocol { 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). + 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. @@ -1788,7 +1794,7 @@ declare module DebugProtocol { 'registers': Scope contains registers. Only a single 'registers' scope should be returned from a 'scopes' request. etc. */ - presentationHint?: string; + presentationHint?: 'arguments' | 'locals' | 'registers' | 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. @@ -1867,7 +1873,7 @@ declare module DebugProtocol { 'dataBreakpoint': Indicates that a data breakpoint is registered for the object. etc. */ - kind?: string; + kind?: 'property' | 'method' | 'class' | 'data' | 'event' | 'baseClass' | 'innerClass' | 'interface' | 'mostDerivedClass' | 'virtual' | 'dataBreakpoint' | 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. @@ -1879,11 +1885,11 @@ declare module DebugProtocol { 'hasSideEffects': Indicates that the evaluation had side effects. etc. */ - attributes?: string[]; + attributes?: ('static' | 'constant' | 'readOnly' | 'rawString' | 'hasObjectId' | 'canHaveObjectId' | 'hasSideEffects' | string)[]; /** Visibility of variable. Before introducing additional values, try to use the listed values. Values: 'public', 'private', 'protected', 'internal', 'final', etc. */ - visibility?: string; + visibility?: 'public' | 'private' | 'protected' | 'internal' | 'final' | string; } /** Properties of a breakpoint location returned from the 'breakpointLocations' request. */ @@ -2108,6 +2114,16 @@ declare module DebugProtocol { includeAll?: boolean; } + /** An ExceptionFilterOptions is used to specify an exception filter together with a condition for the setExceptionsFilter request. */ + export interface ExceptionFilterOptions { + /** ID of an exception filter returned by the 'exceptionBreakpointFilters' capability. */ + filterId: string; + /** An optional expression for conditional exceptions. + The exception will break into the debugger if the result of the condition is true. + */ + condition?: string; + } + /** 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. @@ -2179,11 +2195,13 @@ declare module DebugProtocol { } /** Logical areas that can be invalidated by the 'invalidated' event. + Values: 'all': All previously fetched data has become invalid and needs to be refetched. 'stacks': Previously fetched stack related data has become invalid and needs to be refetched. 'threads': Previously fetched thread related data has become invalid and needs to be refetched. 'variables': Previously fetched variable data has become invalid and needs to be refetched. + etc. */ - export type InvalidatedAreas = 'all' | 'stacks' | 'threads' | 'variables'; + export type InvalidatedAreas = 'all' | 'stacks' | 'threads' | 'variables' | string; } diff --git a/src/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts b/src/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts new file mode 100644 index 00000000000..b6129b8a6ae --- /dev/null +++ b/src/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; +import { EmmetEditorAction } from 'vs/workbench/contrib/emmet/browser/emmetActions'; +import { registerEditorAction } from 'vs/editor/browser/editorExtensions'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { MenuId } from 'vs/platform/actions/common/actions'; + +class ExpandAbbreviationAction extends EmmetEditorAction { + + constructor() { + super({ + id: 'editor.emmet.action.expandAbbreviation', + label: nls.localize('expandAbbreviationAction', "Emmet: Expand Abbreviation"), + alias: 'Emmet: Expand Abbreviation', + precondition: EditorContextKeys.writable, + actionName: 'expand_abbreviation', + kbOpts: { + primary: KeyCode.Tab, + kbExpr: ContextKeyExpr.and( + EditorContextKeys.editorTextFocus, + EditorContextKeys.tabDoesNotMoveFocus, + ContextKeyExpr.has('config.emmet.triggerExpansionOnTab') + ), + weight: KeybindingWeight.EditorContrib + }, + menuOpts: { + menuId: MenuId.MenubarEditMenu, + group: '5_insert', + title: nls.localize({ key: 'miEmmetExpandAbbreviation', comment: ['&& denotes a mnemonic'] }, "Emmet: E&&xpand Abbreviation"), + order: 3 + } + }); + + } +} + +registerEditorAction(ExpandAbbreviationAction); diff --git a/src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts b/src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts index 8d64955f6de..f29d6b2c022 100644 --- a/src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts +++ b/src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts @@ -3,7 +3,5 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerEditorCommand } from 'vs/editor/browser/editorExtensions'; -import { expandEmmetAbbreviationCommand } from './expandEmmetAbbreviation'; +import './actions/expandAbbreviation'; -registerEditorCommand(expandEmmetAbbreviationCommand); diff --git a/src/vs/workbench/contrib/emmet/browser/expandEmmetAbbreviation.ts b/src/vs/workbench/contrib/emmet/browser/emmetActions.ts similarity index 69% rename from src/vs/workbench/contrib/emmet/browser/expandEmmetAbbreviation.ts rename to src/vs/workbench/contrib/emmet/browser/emmetActions.ts index 008f63c289f..607da869cc3 100644 --- a/src/vs/workbench/contrib/emmet/browser/expandEmmetAbbreviation.ts +++ b/src/vs/workbench/contrib/emmet/browser/emmetActions.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ServicesAccessor, EditorCommand } from 'vs/editor/browser/editorExtensions'; +import { EditorAction, ServicesAccessor, IActionOptions } from 'vs/editor/browser/editorExtensions'; import { grammarsExtPoint, ITMSyntaxExtensionPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IExtensionService, ExtensionPointContribution } from 'vs/workbench/services/extensions/common/extensions'; @@ -24,6 +24,7 @@ export interface ILanguageIdentifierResolver { } class GrammarContributions implements IGrammarContributions { + private static _grammars: ModeScopeMap = {}; constructor(contributions: ExtensionPointContribution[]) { @@ -47,12 +48,20 @@ class GrammarContributions implements IGrammarContributions { } } -export class ExpandEmmetAbbreviationCommand extends EditorCommand { - constructor() { - super({ id: 'workbench.action.expandEmmetAbbreviation', precondition: undefined }); +export interface IEmmetActionOptions extends IActionOptions { + actionName: string; +} + +export abstract class EmmetEditorAction extends EditorAction { + + protected emmetActionName: string; + + constructor(opts: IEmmetActionOptions) { + super(opts); + this.emmetActionName = opts.actionName; } - private static readonly emmetSupportedModes = ['html', 'xml', 'xsl', 'jsx', 'js', 'pug', 'slim', 'haml', 'css', 'sass', 'scss', 'less', 'sss', 'stylus']; + private static readonly emmetSupportedModes = ['html', 'css', 'xml', 'xsl', 'haml', 'jade', 'jsx', 'slim', 'scss', 'sass', 'less', 'stylus', 'styl', 'svg']; private _lastGrammarContributions: Promise | null = null; private _lastExtensionService: IExtensionService | null = null; @@ -66,21 +75,20 @@ export class ExpandEmmetAbbreviationCommand extends EditorCommand { return this._lastGrammarContributions || Promise.resolve(null); } - public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise { - if (!accessor) { - return; - } - + public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { const extensionService = accessor.get(IExtensionService); const modeService = accessor.get(IModeService); const commandService = accessor.get(ICommandService); return this._withGrammarContributions(extensionService).then((grammarContributions) => { - if (this.id === 'workbench.action.expandEmmetAbbreviation' && grammarContributions) { - return commandService.executeCommand('editor.emmet.action.expandAbbreviationInternal', ExpandEmmetAbbreviationCommand.getLanguage(modeService, editor, grammarContributions)); + + if (this.id === 'editor.emmet.action.expandAbbreviation' && grammarContributions) { + return commandService.executeCommand('emmet.expandAbbreviation', EmmetEditorAction.getLanguage(modeService, editor, grammarContributions)); } + return undefined; }); + } public static getLanguage(languageIdentifierResolver: ILanguageIdentifierResolver, editor: ICodeEditor, grammars: IGrammarContributions) { @@ -96,34 +104,24 @@ export class ExpandEmmetAbbreviationCommand extends EditorCommand { const languageId = model.getLanguageIdAtPosition(position.lineNumber, position.column); const languageIdentifier = languageIdentifierResolver.getLanguageIdentifier(languageId); const language = languageIdentifier ? languageIdentifier.language : ''; - let syntax = language.split('.').pop(); + const syntax = language.split('.').pop(); if (!syntax) { return null; } - // map to something Emmet understands - if (['jsx-tags', 'javascriptreact', 'typescriptreact'].includes(syntax)) { - syntax = 'jsx'; - } - - const getParentMode = (syntax: string): string => { - if (syntax === 'jsx') { - // return otherwise getGrammar gives a string that Emmet doesn't understand - return syntax; - } - - const languageGrammar = grammars.getGrammar(syntax); + let checkParentMode = (): string => { + let languageGrammar = grammars.getGrammar(syntax); if (!languageGrammar) { return syntax; } - const languages = languageGrammar.split('.'); - if (languages.length <= 1) { + let languages = languageGrammar.split('.'); + if (languages.length < 2) { return syntax; } - for (let i = languages.length - 1; i >= 1; i--) { - const language = languages[i]; - if (this.emmetSupportedModes.includes(language)) { + for (let i = 1; i < languages.length; i++) { + const language = languages[languages.length - i]; + if (this.emmetSupportedModes.indexOf(language) !== -1) { return language; } } @@ -132,9 +130,9 @@ export class ExpandEmmetAbbreviationCommand extends EditorCommand { return { language: syntax, - parentMode: getParentMode(syntax) + parentMode: checkParentMode() }; } -} -export const expandEmmetAbbreviationCommand = new ExpandEmmetAbbreviationCommand(); + +} diff --git a/src/vs/workbench/contrib/emmet/test/browser/expandEmmetAbbreviation.test.ts b/src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts similarity index 57% rename from src/vs/workbench/contrib/emmet/test/browser/expandEmmetAbbreviation.test.ts rename to src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts index 885e1a5064e..c56afa2d157 100644 --- a/src/vs/workbench/contrib/emmet/test/browser/expandEmmetAbbreviation.test.ts +++ b/src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts @@ -3,11 +3,29 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IGrammarContributions, ILanguageIdentifierResolver, ExpandEmmetAbbreviationCommand } from 'vs/workbench/contrib/emmet/browser/expandEmmetAbbreviation'; +import { IGrammarContributions, ILanguageIdentifierResolver, EmmetEditorAction } from 'vs/workbench/contrib/emmet/browser/emmetActions'; import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; import * as assert from 'assert'; import { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes'; +// +// To run the emmet tests only change .vscode/launch.json +// { +// "name": "Stacks Tests", +// "type": "node", +// "request": "launch", +// "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", +// "stopOnEntry": false, +// "args": [ +// "--timeout", +// "999999", +// "--colors", +// "-g", +// "Stacks" <<<--- Emmet +// ], +// Select the 'Stacks Tests' launch config and F5 +// + class MockGrammarContributions implements IGrammarContributions { private scopeName: string; @@ -15,14 +33,16 @@ class MockGrammarContributions implements IGrammarContributions { this.scopeName = scopeName; } - public getGrammar(_: string): string { + public getGrammar(mode: string): string { return this.scopeName; } } -suite('Emmet expandAbbreviation command', () => { - test('gets language mode and parent mode for Emmet', () => { +suite('Emmet', () => { + + test('Get language mode and parent mode for emmet', () => { withTestCodeEditor([], {}, (editor) => { + function testIsEnabled(mode: string, scopeName: string, expectedLanguage?: string, expectedParentLanguage?: string) { const languageIdentifier = new LanguageIdentifier(mode, 73); const languageIdentifierResolver: ILanguageIdentifierResolver = { @@ -39,13 +59,13 @@ suite('Emmet expandAbbreviation command', () => { } model.setMode(languageIdentifier); - const langOutput = ExpandEmmetAbbreviationCommand.getLanguage(languageIdentifierResolver, editor, new MockGrammarContributions(scopeName)); + let langOutput = EmmetEditorAction.getLanguage(languageIdentifierResolver, editor, new MockGrammarContributions(scopeName)); if (!langOutput) { assert.fail('langOutput not found'); } - assert.strictEqual(langOutput.language, expectedLanguage); - assert.strictEqual(langOutput.parentMode, expectedParentLanguage); + assert.equal(langOutput.language, expectedLanguage); + assert.equal(langOutput.parentMode, expectedParentLanguage); } // syntaxes mapped using the scope name of the grammar @@ -54,22 +74,10 @@ suite('Emmet expandAbbreviation command', () => { testIsEnabled('nunjucks', 'text.html.nunjucks', 'nunjucks', 'html'); testIsEnabled('laravel-blade', 'text.html.php.laravel-blade', 'laravel-blade', 'html'); - // basic syntaxes - testIsEnabled('html', 'text.html.derivative', 'html', 'html'); - testIsEnabled('css', 'source.css', 'css', 'css'); - testIsEnabled('scss', 'source.css.scss', 'scss', 'scss'); - testIsEnabled('xml', 'text.xml', 'xml', 'xml'); - testIsEnabled('xsl', 'text.xml.xsl', 'xsl', 'xsl'); + // languages that have different Language Id and scopeName + // testIsEnabled('razor', 'text.html.cshtml', 'razor', 'html'); + // testIsEnabled('HTML (Eex)', 'text.html.elixir', 'boo', 'html'); - // syntaxes that combine HTML and TS/JS - // expanding inside of HTML tags within jsx/tsx - testIsEnabled('jsx-tags', 'source.js.jsx', 'jsx', 'jsx'); - // expanding outside of HTML tags within jsx/tsx - testIsEnabled('javascriptreact', 'source.js.jsx', 'jsx', 'jsx'); - testIsEnabled('typescriptreact', 'source.tsx', 'jsx', 'jsx'); - - // syntaxes that combine HTML and some other language - testIsEnabled('razor', 'text.html.cshtml', 'razor', 'html'); }); }); }); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 992c9b7c86a..5fbd09c9a4d 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -186,6 +186,7 @@ export class ActionWithDropDownAction extends ExtensionAction { super(id, label); this.update(); this._register(Event.any(...actions.map(a => a.onDidChange))(() => this.update(true))); + actions.forEach(a => this._register(a)); } update(donotUpdateActions?: boolean): void { @@ -1803,18 +1804,17 @@ export class ClearExtensionsInputAction extends ClearExtensionsSearchResultsActi id: string, label: string, onSearchChange: Event, - value: string, + getValue: () => string, @IViewsService viewsService: IViewsService ) { super(id, label, viewsService); - this.onSearchChange(value); + this.onSearchChange(getValue()); this._register(onSearchChange(this.onSearchChange, this)); } private onSearchChange(value: string): void { this.enabled = !!value; } - } export class RefreshExtensionsAction extends Action { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 731a2c9aa5e..6b0ed05167f 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -223,10 +223,14 @@ export class Renderer implements IPagedRenderer { }); } }, this, data.extensionDisposables); + } + disposeElement(extension: IExtension, index: number, data: ITemplateData): void { + data.extensionDisposables = dispose(data.extensionDisposables); } disposeTemplate(data: ITemplateData): void { + data.extensionDisposables = dispose(data.extensionDisposables); data.disposables = dispose(data.disposables); } } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 06d74acce15..7fabf9803d5 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -62,6 +62,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { isWeb } from 'vs/base/common/platform'; +import { memoize } from 'vs/base/common/decorators'; const DefaultViewsContext = new RawContextKey('defaultExtensionViews', true); const SearchMarketplaceExtensionsContext = new RawContextKey('searchMarketplaceExtensions', false); @@ -552,39 +553,36 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE return 400; } + @memoize getActions(): IAction[] { - const filterActions: IAction[] = []; - // Local extensions filters - filterActions.push(...[ - this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, localize('builtin filter', "Built-in")), - this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, localize('installed filter', "Installed")), - this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, localize('enabled filter', "Enabled")), - this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, localize('disabled filter', "Disabled")), - this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, localize('outdated filter', "Outdated")), - ]); + let filterActions: IAction[] = [ + this._register(this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, localize('builtin filter', "Built-in"))), + this._register(this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, localize('installed filter', "Installed"))), + this._register(this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, localize('enabled filter', "Enabled"))), + this._register(this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, localize('disabled filter', "Disabled"))), + this._register(this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, localize('outdated filter', "Outdated"))), + ]; if (this.extensionGalleryService.isEnabled()) { - const galleryFilterActions = [ - this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.featured', localize('featured filter', "Featured"), '@featured'), - this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.popular', localize('most popular filter', "Most Popular"), '@popular'), - this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.recommended', localize('most popular recommended', "Recommended"), '@recommended'), - this.instantiationService.createInstance(RecentlyPublishedExtensionsAction, RecentlyPublishedExtensionsAction.ID, localize('recently published filter', "Recently Published")), - new Separator(), - new SubmenuAction('workbench.extensions.action.filterExtensionsByCategory', localize('filter by category', "Category"), EXTENSION_CATEGORIES.map(category => this.instantiationService.createInstance(SearchCategoryAction, `extensions.actions.searchByCategory.${category}`, category, category))), - new Separator(), + filterActions = [ + this._register(this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.featured', localize('featured filter', "Featured"), '@featured')), + this._register(this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.popular', localize('most popular filter', "Most Popular"), '@popular')), + this._register(this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.recommended', localize('most popular recommended', "Recommended"), '@recommended')), + this._register(this.instantiationService.createInstance(RecentlyPublishedExtensionsAction, RecentlyPublishedExtensionsAction.ID, localize('recently published filter', "Recently Published"))), + this._register(new Separator()), + this._register(new SubmenuAction('workbench.extensions.action.filterExtensionsByCategory', localize('filter by category', "Category"), EXTENSION_CATEGORIES.map(category => this.instantiationService.createInstance(SearchCategoryAction, `extensions.actions.searchByCategory.${category}`, category, category)))), + this._register(new Separator()), + ...filterActions, + this._register(new Separator()), + this._register(new SubmenuAction('workbench.extensions.action.sortBy', localize('sorty by', "Sort By"), this.sortActions)), ]; - filterActions.splice(0, 0, ...galleryFilterActions); - filterActions.push(...[ - new Separator(), - new SubmenuAction('workbench.extensions.action.sortBy', localize('sorty by', "Sort By"), this.sortActions), - ]); } return [ - new SubmenuAction('workbench.extensions.action.filterExtensions', localize('filterExtensions', "Filter Extensions..."), filterActions, 'codicon-filter'), - this.instantiationService.createInstance(RefreshExtensionsAction, RefreshExtensionsAction.ID, RefreshExtensionsAction.LABEL), - this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox ? this.searchBox.getValue() : ''), + this._register(new SubmenuAction('workbench.extensions.action.filterExtensions', localize('filterExtensions', "Filter Extensions..."), filterActions, 'codicon-filter')), + this._register(this.instantiationService.createInstance(RefreshExtensionsAction, RefreshExtensionsAction.ID, RefreshExtensionsAction.LABEL)), + this._register(this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, () => this.searchBox!.getValue() || '')), ]; } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput.ts b/src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput.ts rename to src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts index 651b01e8796..1befb2a7fdc 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts @@ -16,7 +16,7 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { randomPort } from 'vs/base/node/ports'; import { IProductService } from 'vs/platform/product/common/productService'; -import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput'; +import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index f7fb0e3bda3..9cf0ec19766 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -17,7 +17,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { RuntimeExtensionsEditor, ShowRuntimeExtensionsAction, IExtensionHostProfileService, DebugExtensionHostAction, StartExtensionHostProfileAction, StopExtensionHostProfileAction, CONTEXT_PROFILE_SESSION_STATE, SaveExtensionHostProfileAction, CONTEXT_EXTENSION_HOST_PROFILE_RECORDED } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor'; import { EditorInput, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, ActiveEditorContext } from 'vs/workbench/common/editor'; import { ExtensionHostProfileService } from 'vs/workbench/contrib/extensions/electron-browser/extensionProfileService'; -import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput'; +import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts index cf44269ccab..d8f182cffbb 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts @@ -16,10 +16,10 @@ import { IExtensionHostProfileService } from 'vs/workbench/contrib/extensions/el import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { localize } from 'vs/nls'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput'; +import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { createSlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions'; +import { createSlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions'; import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions.ts rename to src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index 101597bdee2..c775e9d0042 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -28,7 +28,7 @@ import { memoize } from 'vs/base/common/decorators'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { Event } from 'vs/base/common/event'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput'; +import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; import { IDebugService } from 'vs/workbench/contrib/debug/common/debug'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { randomPort } from 'vs/base/node/ports'; @@ -38,7 +38,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { renderCodicons } from 'vs/base/browser/codicons'; import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { Schemas } from 'vs/base/common/network'; -import { SlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions'; +import { SlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index f4bbf4725f1..de32dad57e7 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -871,7 +871,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { // Native DND if (isNative) { - if (!containsDragType(originalEvent, DataTransfers.FILES, CodeDataTransfers.FILES)) { + if (!containsDragType(originalEvent, DataTransfers.FILES, CodeDataTransfers.FILES, DataTransfers.RESOURCES)) { return false; } } @@ -975,7 +975,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { // The only custom data transfer we set from the explorer is a file transfer // to be able to DND between multiple code file explorers across windows - const fileResources = items.filter(s => !s.isDirectory && s.resource.scheme === Schemas.file).map(r => r.resource.fsPath); + const fileResources = items.filter(s => s.resource.scheme === Schemas.file).map(r => r.resource.fsPath); if (fileResources.length) { originalEvent.dataTransfer.setData(CodeDataTransfers.FILES, JSON.stringify(fileResources)); } @@ -1278,9 +1278,9 @@ export class FileDragAndDrop implements ITreeDragAndDrop { // Pass focus to window this.hostService.focus(); - // Handle folders by adding to workspace if we are in workspace context + // Handle folders by adding to workspace if we are in workspace context and if dropped on top const folders = result.filter(r => r.success && r.stat && r.stat.isDirectory).map(result => ({ uri: result.stat!.resource })); - if (folders.length > 0) { + if (folders.length > 0 && target.isRoot) { const buttons = [ folders.length > 1 ? localize('copyFolders', "&&Copy Folders") : localize('copyFolder', "&&Copy Folder"), localize('cancel', "Cancel") diff --git a/src/vs/workbench/contrib/notebook/browser/constants.ts b/src/vs/workbench/contrib/notebook/browser/constants.ts index 245f72a8786..3232b04744f 100644 --- a/src/vs/workbench/contrib/notebook/browser/constants.ts +++ b/src/vs/workbench/contrib/notebook/browser/constants.ts @@ -22,7 +22,7 @@ export const CELL_TOP_MARGIN = 6; export const CELL_BOTTOM_MARGIN = 6; // Top and bottom padding inside the monaco editor in a cell, which are included in `cell.editorHeight` -export const EDITOR_TOP_PADDING = 12; +// export const EDITOR_TOP_PADDING = 12; export const EDITOR_BOTTOM_PADDING = 4; export const EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR = 12; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index 098838e7112..f18929bbd0e 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -9,7 +9,7 @@ import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/edit import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CellDiffViewModel, PropertyFoldingState } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { CellDiffRenderTemplate, CellDiffViewModelLayoutChangeEvent, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; -import { EDITOR_BOTTOM_PADDING, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; +import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { renderCodicons } from 'vs/base/browser/codicons'; @@ -28,6 +28,7 @@ import { IAction } from 'vs/base/common/actions'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellActionView'; +import { getEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; const fixedEditorOptions: IEditorOptions = { padding: { @@ -758,7 +759,7 @@ export class DeletedCell extends AbstractCellRenderer { const originalCell = this.cell.original!; const lineCount = originalCell.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; - const editorHeight = lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING; + const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; const editorContainer = DOM.append(sourceContainer, DOM.$('.editor-container')); @@ -858,7 +859,7 @@ export class InsertCell extends AbstractCellRenderer { const modifiedCell = this.cell.modified!; const lineCount = modifiedCell.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; - const editorHeight = lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING; + const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; const editorContainer = DOM.append(sourceContainer, DOM.$('.editor-container')); this._editor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, { @@ -962,7 +963,7 @@ export class ModifiedCell extends AbstractCellRenderer { const modifiedCell = this.cell.modified!; const lineCount = modifiedCell.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; - const editorHeight = lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING; + const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; this._editorContainer = DOM.append(sourceContainer, DOM.$('.editor-container')); this._editor = this.instantiationService.createInstance(DiffEditorWidget, this._editorContainer, { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 5db3402f081..0a135c6fed9 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -8,7 +8,7 @@ import { IListContextMenuEvent, IListEvent, IListMouseEvent } from 'vs/base/brow import { IListOptions, IListStyles } from 'vs/base/browser/ui/list/listWidget'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { Event } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ScrollEvent } from 'vs/base/common/scrollable'; import { URI } from 'vs/base/common/uri'; @@ -720,3 +720,17 @@ export function getActiveNotebookEditor(editorService: IEditorService): INoteboo const activeEditorPane = editorService.activeEditorPane as unknown as { isNotebookEditor?: boolean } | undefined; return activeEditorPane?.isNotebookEditor ? (editorService.activeEditorPane?.getControl() as INotebookEditor) : undefined; } + +let EDITOR_TOP_PADDING = 12; +const editorTopPaddingChangeEmitter = new Emitter(); + +export const EditorTopPaddingChangeEvent = editorTopPaddingChangeEmitter.event; + +export function updateEditorTopPadding(top: number) { + EDITOR_TOP_PADDING = top; + editorTopPaddingChangeEmitter.fire(); +} + +export function getEditorTopPadding() { + return EDITOR_TOP_PADDING; +} diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 0e2883e8295..598ea026676 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1354,6 +1354,19 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return new Promise(resolve => { r = resolve; }); } + private _nearestCodeCellIndex(index: number /* exclusive */, direction: 'above' | 'below') { + const nearest = this._notebookViewModel!.viewCells.slice(0, index).reverse().findIndex(cell => cell.cellKind === CellKind.Code); + if (nearest > -1) { + return index - nearest - 1; + } else { + const nearestCellTheOtherDirection = this._notebookViewModel!.viewCells.slice(index + 1).findIndex(cell => cell.cellKind === CellKind.Code); + if (nearestCellTheOtherDirection > -1) { + return index + nearestCellTheOtherDirection; + } + return -1; + } + } + insertNotebookCell(cell: ICellViewModel | undefined, type: CellKind, direction: 'above' | 'below' = 'above', initialText: string = '', ui: boolean = false): CellViewModel | null { if (!this._notebookViewModel!.metadata.editable) { return null; @@ -1361,10 +1374,29 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const index = cell ? this._notebookViewModel!.getCellIndex(cell) : 0; const nextIndex = ui ? this._notebookViewModel!.getNextVisibleCellIndex(index) : index + 1; - const newLanguages = this._notebookViewModel!.resolvedLanguages; - const language = (cell?.cellKind === CellKind.Code && type === CellKind.Code) - ? cell.language - : ((type === CellKind.Code && newLanguages && newLanguages.length) ? newLanguages[0] : 'markdown'); + let language; + if (type === CellKind.Code) { + if (cell?.cellKind === CellKind.Code) { + language = cell.language; + } else if (cell?.cellKind === CellKind.Markdown) { + const nearestCodeCellIndex = this._nearestCodeCellIndex(index, direction); + if (nearestCodeCellIndex > -1) { + language = this._notebookViewModel!.viewCells[nearestCodeCellIndex].language; + } else { + language = this._notebookViewModel!.resolvedLanguages[0] || 'plaintext'; + } + } else { + if (cell === undefined && direction === 'above') { + // insert cell at the very top + language = this._notebookViewModel!.viewCells.find(cell => cell.cellKind === CellKind.Code)?.language || this._notebookViewModel!.resolvedLanguages[0] || 'plaintext'; + } else { + language = this._notebookViewModel!.resolvedLanguages[0] || 'plaintext'; + } + } + } else { + language = 'markdown'; + } + const insertIndex = cell ? (direction === 'above' ? index : nextIndex) : index; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 8179b4ed84d..c2c20888e16 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { getZoomLevel } from 'vs/base/browser/browser'; import { flatten } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; @@ -13,6 +14,9 @@ import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { RedoCommand, UndoCommand } from 'vs/editor/browser/editorExtensions'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { CopyAction, CutAction, PasteAction } from 'vs/editor/contrib/clipboard/clipboard'; import * as nls from 'vs/nls'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -23,7 +27,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol'; import { Memento } from 'vs/workbench/common/memento'; import { INotebookEditorContribution, notebookProviderExtensionPoint, notebookRendererExtensionPoint } from 'vs/workbench/contrib/notebook/browser/extensionPoint'; -import { CellEditState, getActiveNotebookEditor, INotebookEditor, NotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, getActiveNotebookEditor, INotebookEditor, NotebookEditorOptions, updateEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookKernelProviderAssociationRegistry, NotebookViewTypesExtensionRegistry, updateNotebookKernelProvideAssociationSchema } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; @@ -276,7 +280,9 @@ export class NotebookService extends Disposable implements INotebookService, ICu @IConfigurationService private readonly _configurationService: IConfigurationService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, @IStorageService private readonly _storageService: IStorageService, - @IInstantiationService private readonly _instantiationService: IInstantiationService + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(); @@ -336,6 +342,41 @@ export class NotebookService extends Disposable implements INotebookService, ICu updateOrder(); })); + let decorationTriggeredAdjustment = false; + let decorationCheckSet = new Set(); + this._register(this._codeEditorService.onDecorationTypeRegistered(e => { + if (decorationTriggeredAdjustment) { + return; + } + + if (decorationCheckSet.has(e)) { + return; + } + + const options = this._codeEditorService.resolveDecorationOptions(e, true); + if (options.afterContentClassName || options.beforeContentClassName) { + const cssRules = this._codeEditorService.resolveDecorationCSSRules(e); + if (cssRules !== null) { + for (let i = 0; i < cssRules.length; i++) { + // The following ways to index into the list are equivalent + if ( + ((cssRules[i] as CSSStyleRule).selectorText.endsWith('::after') || (cssRules[i] as CSSStyleRule).selectorText.endsWith('::after')) + && (cssRules[i] as CSSStyleRule).cssText.indexOf('top:') > -1 + ) { + // there is a `::before` or `::after` text decoration whose position is above or below current line + // we at least make sure that the editor top padding is at least one line + const editorOptions = this.configurationService.getValue('editor'); + updateEditorTopPadding(BareFontInfo.createFromRawSettings(editorOptions, getZoomLevel()).lineHeight + 2); + decorationTriggeredAdjustment = true; + break; + } + } + } + } + + decorationCheckSet.add(e); + })); + const getContext = () => { const editor = getActiveNotebookEditor(this._editorService); const activeCell = editor?.getActiveCell(); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 62aa3a4f1ab..9c54b9cbd8c 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -35,9 +35,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { BOTTOM_CELL_TOOLBAR_GAP, CELL_BOTTOM_MARGIN, CELL_TOP_MARGIN, EDITOR_BOTTOM_PADDING, EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; +import { BOTTOM_CELL_TOOLBAR_GAP, CELL_BOTTOM_MARGIN, CELL_TOP_MARGIN, EDITOR_BOTTOM_PADDING, EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR, EDITOR_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants'; import { CancelCellAction, DeleteCellAction, ExecuteCellAction, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; -import { BaseCellRenderTemplate, CellEditState, CodeCellRenderTemplate, EXPAND_CELL_CONTENT_COMMAND_ID, ICellViewModel, INotebookEditor, isCodeCellRenderTemplate, MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { BaseCellRenderTemplate, CellEditState, CodeCellRenderTemplate, EditorTopPaddingChangeEvent, EXPAND_CELL_CONTENT_COMMAND_ID, getEditorTopPadding, ICellViewModel, INotebookEditor, isCodeCellRenderTemplate, MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys'; import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus'; import { CellEditorStatusBar } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; @@ -117,10 +117,16 @@ export class CellEditorOptions { } }); + EditorTopPaddingChangeEvent(() => { + this._value = computeEditorOptions(); + this._onDidChange.fire(this.value); + + }); + const computeEditorOptions = () => { const showCellStatusBar = configurationService.getValue(ShowCellStatusBarKey); const editorPadding = { - top: EDITOR_TOP_PADDING, + top: getEditorTopPadding(), bottom: showCellStatusBar ? EDITOR_BOTTOM_PADDING : EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR }; @@ -717,7 +723,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende }, {}); disposables.add(this.editorOptions.onDidChange(newValue => editor.updateOptions(newValue))); - const { collapsedPart, expandButton } = this.setupCollapsedPart(container); const progressBar = new ProgressBar(editorPart); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts index d876198e3fe..f86890dedba 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts @@ -11,8 +11,8 @@ import { IDimension } from 'vs/editor/common/editorCommon'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { EDITOR_BOTTOM_PADDING, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellFocusMode, CodeCellRenderTemplate, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CellFocusMode, CodeCellRenderTemplate, getEditorTopPadding, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -46,7 +46,7 @@ export class CodeCell extends Disposable { const lineNum = this.viewCell.lineCount; const lineHeight = this.viewCell.layoutInfo.fontInfo?.lineHeight || 17; const editorHeight = this.viewCell.layoutInfo.editorHeight === 0 - ? lineNum * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING + ? lineNum * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING : this.viewCell.layoutInfo.editorHeight; this.layoutEditor( diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts index bbdf6f99ec0..cd949babf5b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts @@ -11,8 +11,8 @@ import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { EDITOR_BOTTOM_PADDING, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFocusMode, INotebookEditor, MarkdownCellRenderTemplate, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CellEditState, CellFocusMode, INotebookEditor, MarkdownCellRenderTemplate, ICellViewModel, getEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellFoldingState } from 'vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel'; import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -214,7 +214,7 @@ export class StatefulMarkdownCell extends Disposable { const width = this.viewCell.layoutInfo.editorWidth; const lineNum = this.viewCell.lineCount; const lineHeight = this.viewCell.layoutInfo.fontInfo?.lineHeight || 17; - editorHeight = Math.max(lineNum, 1) * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING; + editorHeight = Math.max(lineNum, 1) * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; this.templateData.editorContainer.innerText = ''; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index c29832730a0..936792e8a50 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -137,14 +137,27 @@ function webviewPreloads() { } if (entry.target.id === id && entry.contentRect) { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'dimension', - id: id, - data: { - height: entry.contentRect.height + __outputNodePadding__ * 2 - } - }); + if (entry.contentRect.height !== 0) { + entry.target.style.padding = `${__outputNodePadding__}px`; + vscode.postMessage({ + __vscode_notebook_message: true, + type: 'dimension', + id: id, + data: { + height: entry.contentRect.height + __outputNodePadding__ * 2 + } + }); + } else { + entry.target.style.padding = `0px`; + vscode.postMessage({ + __vscode_notebook_message: true, + type: 'dimension', + id: id, + data: { + height: entry.contentRect.height + } + }); + } } } }); @@ -410,7 +423,8 @@ function webviewPreloads() { outputNode.style.top = data.top + 'px'; outputNode.style.left = data.left + 'px'; outputNode.style.width = 'calc(100% - ' + data.left + 'px)'; - outputNode.style.minHeight = '32px'; + // outputNode.style.minHeight = '32px'; + outputNode.style.padding = '0px'; outputNode.id = outputId; addMouseoverListeners(outputNode, outputId); diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts index d49dc929cb0..3d4b3b4e522 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts @@ -12,8 +12,8 @@ import { IPosition } from 'vs/editor/common/core/position'; import * as editorCommon from 'vs/editor/common/editorCommon'; import * as model from 'vs/editor/common/model'; import { SearchParams } from 'vs/editor/common/model/textModelSearch'; -import { CELL_STATUSBAR_HEIGHT, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFocusMode, CursorAtBoundary, CellViewModelStateChangeEvent, IEditableCellViewModel, INotebookCellDecorationOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CELL_STATUSBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CellEditState, CellFocusMode, CursorAtBoundary, CellViewModelStateChangeEvent, IEditableCellViewModel, INotebookCellDecorationOptions, getEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellKind, NotebookCellMetadata, NotebookDocumentMetadata, INotebookSearchOptions, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -341,7 +341,7 @@ export abstract class BaseCellViewModel extends Disposable { return 0; } - return this._textEditor.getTopForLineNumber(line) + EDITOR_TOP_PADDING; + return this._textEditor.getTopForLineNumber(line) + getEditorTopPadding(); } getPositionScrollTopOffset(line: number, column: number): number { @@ -349,7 +349,7 @@ export abstract class BaseCellViewModel extends Disposable { return 0; } - return this._textEditor.getTopForPosition(line, column) + EDITOR_TOP_PADDING; + return this._textEditor.getTopForPosition(line, column) + getEditorTopPadding(); } cursorAtBeginEnd(): boolean { diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index eee92f542e5..0760fbf4d82 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -9,8 +9,8 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import * as model from 'vs/editor/common/model'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo, CodeCellLayoutState, ICellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CellEditState, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo, CodeCellLayoutState, getEditorTopPadding, ICellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { CellKind, INotebookSearchOptions, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -221,7 +221,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod } private estimateEditorHeight(lineHeight: number | undefined = 20): number { - return this.lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING; + return this.lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; } private computeTotalHeight(editorHeight: number, outputsTotalHeight: number, outputShowMoreContainerHeight: number): number { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 790e22901d5..64d3da690d3 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -46,7 +46,7 @@ import { AbstractSettingRenderer, ISettingLinkClickEvent, ISettingOverrideClickE import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree'; -import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, FEATURE_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/contrib/preferences/common/preferences'; +import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, FEATURE_SETTING_TAG, ID_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/contrib/preferences/common/preferences'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingsEditorOptions, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; @@ -90,7 +90,7 @@ export class SettingsEditor2 extends EditorPane { private static CONFIG_SCHEMA_UPDATE_DELAYER = 500; private static readonly SUGGESTIONS: string[] = [ - `@${MODIFIED_SETTING_TAG}`, '@tag:usesOnlineServices', '@tag:sync', `@${EXTENSION_SETTING_TAG}`, `@${FEATURE_SETTING_TAG}scm`, `@${FEATURE_SETTING_TAG}explorer`, `@${FEATURE_SETTING_TAG}search`, `@${FEATURE_SETTING_TAG}debug`, `@${FEATURE_SETTING_TAG}extensions`, `@${FEATURE_SETTING_TAG}terminal`, `@${FEATURE_SETTING_TAG}task`, `@${FEATURE_SETTING_TAG}problems`, `@${FEATURE_SETTING_TAG}output`, `@${FEATURE_SETTING_TAG}comments`, `@${FEATURE_SETTING_TAG}remote`, `@${FEATURE_SETTING_TAG}timeline` + `@${MODIFIED_SETTING_TAG}`, '@tag:usesOnlineServices', '@tag:sync', `@${ID_SETTING_TAG}`, `@${EXTENSION_SETTING_TAG}`, `@${FEATURE_SETTING_TAG}scm`, `@${FEATURE_SETTING_TAG}explorer`, `@${FEATURE_SETTING_TAG}search`, `@${FEATURE_SETTING_TAG}debug`, `@${FEATURE_SETTING_TAG}extensions`, `@${FEATURE_SETTING_TAG}terminal`, `@${FEATURE_SETTING_TAG}task`, `@${FEATURE_SETTING_TAG}problems`, `@${FEATURE_SETTING_TAG}output`, `@${FEATURE_SETTING_TAG}comments`, `@${FEATURE_SETTING_TAG}remote`, `@${FEATURE_SETTING_TAG}timeline` ]; private static shouldSettingUpdateFast(type: SettingValueType | SettingValueType[]): boolean { @@ -1135,19 +1135,21 @@ export class SettingsEditor2 extends EditorPane { this.viewState.tagFilters = new Set(); this.viewState.extensionFilters = new Set(); this.viewState.featureFilters = new Set(); + this.viewState.idFilters = new Set(); if (query) { const parsedQuery = parseQuery(query); query = parsedQuery.query; parsedQuery.tags.forEach(tag => this.viewState.tagFilters!.add(tag)); parsedQuery.extensionFilters.forEach(extensionId => this.viewState.extensionFilters!.add(extensionId)); parsedQuery.featureFilters!.forEach(feature => this.viewState.featureFilters!.add(feature)); + parsedQuery.idFilters!.forEach(id => this.viewState.idFilters!.add(id)); } if (query && query !== '@') { query = this.parseSettingFromJSON(query) || query; return this.triggerFilterPreferences(query); } else { - if (this.viewState.tagFilters.size || this.viewState.extensionFilters.size || this.viewState.featureFilters.size) { + if (this.viewState.tagFilters.size || this.viewState.extensionFilters.size || this.viewState.featureFilters.size || this.viewState.idFilters.size) { this.searchResultModel = this.createFilterModel(); } else { this.searchResultModel = null; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index 94cf0a3cb1b..e2f231a83e3 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -26,6 +26,7 @@ export interface ISettingsEditorViewState { tagFilters?: Set; extensionFilters?: Set; featureFilters?: Set; + idFilters?: Set; filterToCategory?: SettingsTreeGroupElement; } @@ -311,6 +312,13 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { } }); } + + matchesAnyId(idFilters?: Set): boolean { + if (!idFilters || !idFilters.size) { + return true; + } + return idFilters.has(this.setting.key); + } } @@ -641,7 +649,7 @@ export class SearchResultModel extends SettingsTreeModel { const isRemote = !!this.environmentService.remoteAuthority; this.root.children = this.root.children - .filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAnyExtension(this._viewState.extensionFilters) && this.containsValidFeature() ? child.matchesAnyFeature(this._viewState.featureFilters) : true); + .filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAnyExtension(this._viewState.extensionFilters) && child.matchesAnyId(this._viewState.idFilters) && (this.containsValidFeature() ? child.matchesAnyFeature(this._viewState.featureFilters) : true)); if (this.newExtensionSearchResults && this.newExtensionSearchResults.filterMatches.length) { const resultExtensionIds = this.newExtensionSearchResults.filterMatches @@ -687,16 +695,19 @@ export interface IParsedQuery { tags: string[]; query: string; extensionFilters: string[]; + idFilters: string[]; featureFilters: string[]; } const tagRegex = /(^|\s)@tag:("([^"]*)"|[^"]\S*)/g; const extensionRegex = /(^|\s)@ext:("([^"]*)"|[^"]\S*)?/g; const featureRegex = /(^|\s)@feature:("([^"]*)"|[^"]\S*)?/g; +const idRegex = /(^|\s)@id:("([^"]*)"|[^"]\S*)?/g; export function parseQuery(query: string): IParsedQuery { const tags: string[] = []; const extensions: string[] = []; const features: string[] = []; + const ids: string[] = []; query = query.replace(tagRegex, (_, __, quotedTag, tag) => { tags.push(tag || quotedTag); return ''; @@ -723,12 +734,21 @@ export function parseQuery(query: string): IParsedQuery { return ''; }); + query = query.replace(idRegex, (_, __, quotedId, id) => { + const idRegex: string = id || quotedId; + if (idRegex) { + ids.push(...idRegex.split(',').map(s => s.trim()).filter(s => !isFalsyOrWhitespace(s))); + } + return ''; + }); + query = query.trim(); return { tags, extensionFilters: extensions, featureFilters: features, + idFilters: ids, query }; } diff --git a/src/vs/workbench/contrib/preferences/browser/tocTree.ts b/src/vs/workbench/contrib/preferences/browser/tocTree.ts index 3888aad4803..edb880108f3 100644 --- a/src/vs/workbench/contrib/preferences/browser/tocTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/tocTree.ts @@ -93,7 +93,8 @@ export class TOCTreeModel { return child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAllTags(this._viewState.tagFilters) && child.matchesAnyFeature(this._viewState.featureFilters) && - child.matchesAnyExtension(this._viewState.extensionFilters); + child.matchesAnyExtension(this._viewState.extensionFilters) && + child.matchesAnyId(this._viewState.idFilters); }).length; } } diff --git a/src/vs/workbench/contrib/preferences/common/preferences.ts b/src/vs/workbench/contrib/preferences/common/preferences.ts index ca97a3d6414..928106092b3 100644 --- a/src/vs/workbench/contrib/preferences/common/preferences.ts +++ b/src/vs/workbench/contrib/preferences/common/preferences.ts @@ -71,4 +71,5 @@ export const KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS = 'keybindings.editor.show export const MODIFIED_SETTING_TAG = 'modified'; export const EXTENSION_SETTING_TAG = 'ext:'; export const FEATURE_SETTING_TAG = 'feature:'; +export const ID_SETTING_TAG = 'id:'; export const KEYBOARD_LAYOUT_OPEN_PICKER = 'workbench.action.openKeyboardLayoutPicker'; diff --git a/src/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts b/src/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts index 7387f4519cb..b2ae0a9e85b 100644 --- a/src/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts +++ b/src/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts @@ -147,8 +147,9 @@ suite('SettingsTree', () => { { tags: [], extensionFilters: [], + query: '', featureFilters: [], - query: '' + idFilters: [] }); testParseQuery( @@ -156,8 +157,9 @@ suite('SettingsTree', () => { { tags: ['modified'], extensionFilters: [], + query: '', featureFilters: [], - query: '' + idFilters: [] }); testParseQuery( @@ -165,8 +167,9 @@ suite('SettingsTree', () => { { tags: ['foo'], extensionFilters: [], + query: '', featureFilters: [], - query: '' + idFilters: [] }); testParseQuery( @@ -174,8 +177,9 @@ suite('SettingsTree', () => { { tags: ['modified'], extensionFilters: [], + query: 'foo', featureFilters: [], - query: 'foo' + idFilters: [] }); testParseQuery( @@ -183,8 +187,9 @@ suite('SettingsTree', () => { { tags: ['foo', 'modified'], extensionFilters: [], + query: '', featureFilters: [], - query: '' + idFilters: [] }); testParseQuery( @@ -192,8 +197,9 @@ suite('SettingsTree', () => { { tags: ['foo', 'modified'], extensionFilters: [], + query: 'my query', featureFilters: [], - query: 'my query' + idFilters: [] }); testParseQuery( @@ -201,8 +207,9 @@ suite('SettingsTree', () => { { tags: ['modified'], extensionFilters: [], + query: 'test query', featureFilters: [], - query: 'test query' + idFilters: [] }); testParseQuery( @@ -210,8 +217,9 @@ suite('SettingsTree', () => { { tags: ['modified'], extensionFilters: [], + query: 'test', featureFilters: [], - query: 'test' + idFilters: [] }); testParseQuery( @@ -221,6 +229,7 @@ suite('SettingsTree', () => { extensionFilters: [], query: 'query has @ for some reason', featureFilters: [], + idFilters: [] }); testParseQuery( @@ -228,8 +237,9 @@ suite('SettingsTree', () => { { tags: [], extensionFilters: ['github.vscode-pull-request-github'], + query: '', featureFilters: [], - query: '' + idFilters: [] }); testParseQuery( @@ -237,8 +247,9 @@ suite('SettingsTree', () => { { tags: [], extensionFilters: ['github.vscode-pull-request-github', 'vscode.git'], + query: '', featureFilters: [], - query: '' + idFilters: [] }); testParseQuery( '@feature:scm', @@ -246,7 +257,8 @@ suite('SettingsTree', () => { tags: [], extensionFilters: [], featureFilters: ['scm'], - query: '' + query: '', + idFilters: [] }); testParseQuery( @@ -255,7 +267,27 @@ suite('SettingsTree', () => { tags: [], extensionFilters: [], featureFilters: ['scm', 'terminal'], - query: '' + query: '', + idFilters: [] + }); + testParseQuery( + '@id:files.autoSave', + { + tags: [], + extensionFilters: [], + featureFilters: [], + query: '', + idFilters: ['files.autoSave'] + }); + + testParseQuery( + '@id:files.autoSave,terminal.integrated.commandsToSkipShell', + { + tags: [], + extensionFilters: [], + featureFilters: [], + query: '', + idFilters: ['files.autoSave', 'terminal.integrated.commandsToSkipShell'] }); }); }); diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index 4eb693366fb..70e167d1245 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -6,8 +6,8 @@ import * as nls from 'vs/nls'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Extensions, IViewDescriptorService, IViewsRegistry, IViewsService } from 'vs/workbench/common/views'; -import { IRemoteExplorerService, MakeAddress, mapHasTunnelLocalhostOrAllInterfaces, TUNNEL_VIEW_ID } from 'vs/workbench/services/remote/common/remoteExplorerService'; -import { forwardedPortsViewEnabled, ForwardPortAction, OpenPortInBrowserAction, TunnelPanelDescriptor, TunnelViewModel } from 'vs/workbench/contrib/remote/browser/tunnelView'; +import { IRemoteExplorerService, makeAddress, mapHasAddressLocalhostOrAllInterfaces, TUNNEL_VIEW_ID } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { forwardedPortsViewEnabled, ForwardPortAction, OpenPortInBrowserAction, TunnelPanel, TunnelPanelDescriptor, TunnelViewModel } from 'vs/workbench/contrib/remote/browser/tunnelView'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -15,10 +15,13 @@ import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarA import { UrlFinder } from 'vs/workbench/contrib/remote/browser/urlFinder'; import Severity from 'vs/base/common/severity'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification'; +import { INotificationHandle, INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { OperatingSystem } from 'vs/base/common/platform'; +import { RemoteTunnel } from 'vs/platform/remote/common/tunnel'; export const VIEWLET_ID = 'workbench.view.remote'; @@ -117,36 +120,103 @@ export class ForwardedPortsView extends Disposable implements IWorkbenchContribu export class AutomaticPortForwarding extends Disposable implements IWorkbenchContribution { - private contextServiceListener?: IDisposable; - private urlFinder?: UrlFinder; - private static AUTO_FORWARD_SETTING = 'remote.autoForwardPorts'; + static AUTO_FORWARD_SETTING = 'remote.autoForwardPorts'; constructor( - @ITerminalService private readonly terminalService: ITerminalService, - @INotificationService private readonly notificationService: INotificationService, - @IOpenerService private readonly openerService: IOpenerService, - @IViewsService private readonly viewsService: IViewsService, - @IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IDebugService private readonly debugService: IDebugService + @ITerminalService readonly terminalService: ITerminalService, + @INotificationService readonly notificationService: INotificationService, + @IOpenerService readonly openerService: IOpenerService, + @IViewsService readonly viewsService: IViewsService, + @IRemoteExplorerService readonly remoteExplorerService: IRemoteExplorerService, + @IWorkbenchEnvironmentService readonly environmentService: IWorkbenchEnvironmentService, + @IContextKeyService readonly contextKeyService: IContextKeyService, + @IConfigurationService readonly configurationService: IConfigurationService, + @IDebugService readonly debugService: IDebugService, + @IRemoteAgentService readonly remoteAgentService: IRemoteAgentService ) { super(); + if (!this.environmentService.remoteAuthority) { + return; + } + + remoteAgentService.getEnvironment().then(environment => { + if (environment?.os === OperatingSystem.Windows) { + this._register(new WindowsAutomaticPortForwarding(terminalService, notificationService, openerService, + remoteExplorerService, contextKeyService, configurationService, debugService)); + } else if (environment?.os === OperatingSystem.Linux) { + this._register(new LinuxAutomaticPortForwarding(configurationService, remoteExplorerService, notificationService, openerService)); + } + }); + } +} + +class ForwardedPortNotifier extends Disposable { + private lastNotifyTime: Date; + private static COOL_DOWN = 5000; // milliseconds + private lastNotification: INotificationHandle | undefined; + + constructor(private readonly notificationService: INotificationService, + private readonly remoteExplorerService: IRemoteExplorerService, + private readonly openerService: IOpenerService) { + super(); + this.lastNotifyTime = new Date(); + this.lastNotifyTime.setFullYear(this.lastNotifyTime.getFullYear() - 1); + } + + public notify(tunnels: RemoteTunnel[]) { + if (Date.now() - this.lastNotifyTime.getTime() > ForwardedPortNotifier.COOL_DOWN) { + this.showNotification(tunnels); + } + } + + private showNotification(tunnels: RemoteTunnel[]) { + if (tunnels.length === 0) { + return; + } + tunnels = tunnels.sort((a, b) => a.tunnelRemotePort - b.tunnelRemotePort); + const firstTunnel = tunnels.shift()!; + const address = makeAddress(firstTunnel.tunnelRemoteHost, firstTunnel.tunnelRemotePort); + const message = nls.localize('remote.tunnelsView.automaticForward', "Your service running on port {0} is available. [See all available ports](command:{1}.focus)", + firstTunnel.tunnelRemotePort, TunnelPanel.ID); + const browserChoice: IPromptChoice = { + label: OpenPortInBrowserAction.LABEL, + run: () => OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, this.openerService, address) + }; + this.lastNotification = this.notificationService.prompt(Severity.Info, message, [browserChoice], { neverShowAgain: { id: 'remote.tunnelsView.autoForwardNeverShow', isSecondary: true } }); + this.lastNotification.onDidClose(() => { + this.lastNotification = undefined; + }); + } +} + +class WindowsAutomaticPortForwarding extends Disposable { + private contextServiceListener?: IDisposable; + private urlFinder?: UrlFinder; + private notifier: ForwardedPortNotifier; + + constructor( + private readonly terminalService: ITerminalService, + readonly notificationService: INotificationService, + readonly openerService: IOpenerService, + private readonly remoteExplorerService: IRemoteExplorerService, + private readonly contextKeyService: IContextKeyService, + private readonly configurationService: IConfigurationService, + private readonly debugService: IDebugService + ) { + super(); + this.notifier = new ForwardedPortNotifier(notificationService, remoteExplorerService, openerService); this._register(configurationService.onDidChangeConfiguration((e) => { if (e.affectsConfiguration(AutomaticPortForwarding.AUTO_FORWARD_SETTING)) { this.tryStartStopUrlFinder(); } })); - if (this.environmentService.remoteAuthority) { - this.contextServiceListener = this._register(this.contextKeyService.onDidChangeContext(e => { - if (e.affectsSome(new Set(forwardedPortsViewEnabled.keys()))) { - this.tryStartStopUrlFinder(); - } - })); - this.tryStartStopUrlFinder(); - } + this.contextServiceListener = this._register(this.contextKeyService.onDidChangeContext(e => { + if (e.affectsSome(new Set(forwardedPortsViewEnabled.keys()))) { + this.tryStartStopUrlFinder(); + } + })); + this.tryStartStopUrlFinder(); } private tryStartStopUrlFinder() { @@ -166,31 +236,12 @@ export class AutomaticPortForwarding extends Disposable implements IWorkbenchCon } this.urlFinder = this._register(new UrlFinder(this.terminalService, this.debugService)); this._register(this.urlFinder.onDidMatchLocalUrl(async (localUrl) => { - if (mapHasTunnelLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, localUrl.host, localUrl.port)) { + if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, localUrl.host, localUrl.port)) { return; } const forwarded = await this.remoteExplorerService.forward(localUrl); if (forwarded) { - const address = MakeAddress(forwarded.tunnelRemoteHost, forwarded.tunnelRemotePort); - const message = nls.localize('remote.tunnelsView.automaticForward', "Your service running on port {0} is available.", - forwarded.tunnelRemotePort); - const browserChoice: IPromptChoice = { - label: OpenPortInBrowserAction.LABEL, - run: () => OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, this.openerService, address) - }; - const showChoice: IPromptChoice = { - label: nls.localize('remote.tunnelsView.showView', "Show Forwarded Ports"), - run: () => { - const remoteAuthority = this.environmentService.remoteAuthority; - const explorerType: string[] | undefined = remoteAuthority ? [remoteAuthority.split('+')[0]] : undefined; - if (explorerType) { - this.remoteExplorerService.targetType = explorerType; - } - this.viewsService.openViewContainer(VIEWLET_ID); - }, - isSecondary: true - }; - this.notificationService.prompt(Severity.Info, message, [browserChoice, showChoice], { neverShowAgain: { id: 'remote.tunnelsView.autoForwardNeverShow', isSecondary: true } }); + this.notifier.notify([forwarded]); } })); } @@ -202,3 +253,93 @@ export class AutomaticPortForwarding extends Disposable implements IWorkbenchCon } } } + +class LinuxAutomaticPortForwarding extends Disposable { + private candidateListener: IDisposable | undefined; + private autoForwarded: Set = new Set(); + private notifier: ForwardedPortNotifier; + private initialCandidates: Set = new Set(); + + constructor( + private readonly configurationService: IConfigurationService, + readonly remoteExplorerService: IRemoteExplorerService, + readonly notificationService: INotificationService, + readonly openerService: IOpenerService + ) { + super(); + this.notifier = new ForwardedPortNotifier(notificationService, remoteExplorerService, openerService); + this._register(configurationService.onDidChangeConfiguration((e) => { + if (e.affectsConfiguration(AutomaticPortForwarding.AUTO_FORWARD_SETTING)) { + this.startStopCandidateListener(); + } + })); + + this.startStopCandidateListener(); + } + + private startStopCandidateListener() { + if (this.configurationService.getValue(AutomaticPortForwarding.AUTO_FORWARD_SETTING)) { + this.startCandidateListener(); + } else { + this.stopCandidateListener(); + } + } + + private stopCandidateListener() { + if (this.candidateListener) { + this.candidateListener.dispose(); + this.candidateListener = undefined; + } + } + + private startCandidateListener() { + if (this.candidateListener) { + // already started + return; + } + + this.candidateListener = this._register(this.remoteExplorerService.tunnelModel.onCandidatesChanged(this.handleCandidateUpdate, this)); + // Capture list of starting candidates so we don't auto forward them later. + this.setInitialCandidates(); + } + + private setInitialCandidates() { + this.remoteExplorerService.tunnelModel.candidates.forEach(async (value) => { + this.initialCandidates.add(makeAddress(value.host, value.port)); + }); + } + + private async forwardCandidates(): Promise { + const allTunnels = (await Promise.all(this.remoteExplorerService.tunnelModel.candidates.map(async (value) => { + const address = makeAddress(value.host, value.port); + if (this.initialCandidates.has(address)) { + return undefined; + } + const forwarded = await this.remoteExplorerService.forward(value); + if (forwarded) { + this.autoForwarded.add(address); + } + return forwarded; + }))).filter(tunnel => !!tunnel); + if (allTunnels.length === 0) { + return undefined; + } + return allTunnels; + } + + private async handleCandidateUpdate(removed: Map) { + removed.forEach((value, key) => { + if (this.autoForwarded.has(key)) { + this.remoteExplorerService.close(value); + this.autoForwarded.delete(key); + } else if (this.initialCandidates.has(key)) { + this.initialCandidates.delete(key); + } + }); + + const tunnels = await this.forwardCandidates(); + if (tunnels) { + this.notifier.notify(tunnels); + } + } +} diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index 52018fae5a6..61f640248b8 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -26,7 +26,7 @@ import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { ActionRunner, IAction } from 'vs/base/common/actions'; import { IMenuService, MenuId, IMenu, MenuRegistry, MenuItemAction, ILocalizedString, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { createAndFillInContextMenuActions, createAndFillInActionBarActions, MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IRemoteExplorerService, TunnelModel, MakeAddress, TunnelType, ITunnelItem, Tunnel, mapHasTunnelLocalhostOrAllInterfaces, TUNNEL_VIEW_ID } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { IRemoteExplorerService, TunnelModel, makeAddress, TunnelType, ITunnelItem, Tunnel, mapHasAddressLocalhostOrAllInterfaces, TUNNEL_VIEW_ID, parseAddress } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -92,7 +92,7 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel { const groups: ITunnelGroup[] = []; this._candidates = new Map(); (await this.model.candidates).forEach(candidate => { - this._candidates.set(MakeAddress(candidate.host, candidate.port), candidate); + this._candidates.set(makeAddress(candidate.host, candidate.port), candidate); }); if ((this.model.forwarded.size > 0) || this.remoteExplorerService.getEditableData(undefined)) { groups.push({ @@ -123,7 +123,7 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel { } private addProcessInfoFromCandidate(tunnelItem: ITunnelItem) { - const key = MakeAddress(tunnelItem.remoteHost, tunnelItem.remotePort); + const key = makeAddress(tunnelItem.remoteHost, tunnelItem.remotePort); if (this._candidates.has(key)) { tunnelItem.description = this._candidates.get(key)!.detail; } @@ -158,8 +158,8 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel { get candidates(): TunnelItem[] { const candidates: TunnelItem[] = []; this._candidates.forEach(value => { - if (!mapHasTunnelLocalhostOrAllInterfaces(this.model.forwarded, value.host, value.port) && - !mapHasTunnelLocalhostOrAllInterfaces(this.model.detected, value.host, value.port)) { + if (!mapHasAddressLocalhostOrAllInterfaces(this.model.forwarded, value.host, value.port) && + !mapHasAddressLocalhostOrAllInterfaces(this.model.detected, value.host, value.port)) { candidates.push(new TunnelItem(TunnelType.Candidate, value.host, value.port, undefined, undefined, false, undefined, value.detail)); } }); @@ -387,7 +387,7 @@ interface ITunnelGroup { class TunnelItem implements ITunnelItem { static createFromTunnel(tunnel: Tunnel, type: TunnelType = TunnelType.Forwarded, closeable?: boolean) { - return new TunnelItem(type, tunnel.remoteHost, tunnel.remotePort, tunnel.localAddress, tunnel.localPort, closeable === undefined ? tunnel.closeable : closeable, tunnel.name, tunnel.description); + return new TunnelItem(type, tunnel.remoteHost, tunnel.remotePort, tunnel.localAddress, tunnel.localPort, closeable === undefined ? tunnel.closeable : closeable, tunnel.name, tunnel.description ?? tunnel.runningProcess); } constructor( @@ -750,16 +750,8 @@ export namespace ForwardPortAction { export const TREEITEM_LABEL = nls.localize('remote.tunnel.forwardItem', "Forward Port"); const forwardPrompt = nls.localize('remote.tunnel.forwardPrompt', "Port number or address (eg. 3000 or 10.10.10.10:2000)."); - function parseInput(value: string): { host: string, port: number } | undefined { - const matches = value.match(/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\:|localhost:)?([0-9]+)$/); - if (!matches) { - return undefined; - } - return { host: matches[1]?.substring(0, matches[1].length - 1) || 'localhost', port: Number(matches[2]) }; - } - function validateInput(value: string): string | null { - const parsed = parseInput(value); + const parsed = parseAddress(value); if (!parsed) { return invalidPortString; } else if (parsed.port >= maxPortNumber) { @@ -784,7 +776,7 @@ export namespace ForwardPortAction { remoteExplorerService.setEditable(undefined, { onFinish: async (value, success) => { let parsed: { host: string, port: number } | undefined; - if (success && (parsed = parseInput(value))) { + if (success && (parsed = parseAddress(value))) { remoteExplorerService.forward({ host: parsed.host, port: parsed.port }).then(tunnel => error(notificationService, tunnel, parsed!.host, parsed!.port)); } remoteExplorerService.setEditable(undefined, null); @@ -808,7 +800,7 @@ export namespace ForwardPortAction { validateInput: (value) => Promise.resolve(validateInput(value)) }); let parsed: { host: string, port: number } | undefined; - if (value && (parsed = parseInput(value))) { + if (value && (parsed = parseAddress(value))) { remoteExplorerService.forward({ host: parsed.host, port: parsed.port }).then(tunnel => error(notificationService, tunnel, parsed!.host, parsed!.port)); } }; @@ -874,10 +866,15 @@ export namespace OpenPortInBrowserAction { export function handler(): ICommandHandler { return async (accessor, arg) => { + let key: string | undefined; if (arg instanceof TunnelItem) { + key = makeAddress(arg.remoteHost, arg.remotePort); + } else if (arg.tunnelRemoteHost && arg.tunnelRemotePort) { + key = makeAddress(arg.tunnelRemoteHost, arg.tunnelRemotePort); + } + if (key) { const model = accessor.get(IRemoteExplorerService).tunnelModel; const openerService = accessor.get(IOpenerService); - const key = MakeAddress(arg.remoteHost, arg.remotePort); return run(model, openerService, key); } }; diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index b2907e2e71f..b23b1174083 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -1063,12 +1063,14 @@ class ViewModel { } focus() { - for (const repository of this.scmViewService.visibleRepositories) { - const widget = this.inputRenderer.getRenderedInputWidget(repository.input); + if (this.tree.getFocus().length === 0) { + for (const repository of this.scmViewService.visibleRepositories) { + const widget = this.inputRenderer.getRenderedInputWidget(repository.input); - if (widget) { - widget.focus(); - return; + if (widget) { + widget.focus(); + return; + } } } diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index d66b3b50b7b..35f0c4bde49 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -1703,7 +1703,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return; } - if (contributed.length === 0) { + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { result.add(key, ...folderTasks.set.tasks); } else { let configurations = folderTasks.configurations; diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 7e5a1114930..4a4becc173e 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -858,7 +858,6 @@ export class TerminalTaskSystem implements ITaskSystem { }); promise = new Promise((resolve, reject) => { const onExit = terminal!.onExit((exitCode) => { - onData.dispose(); onExit.dispose(); let key = task.getMapKey(); this.removeFromActiveTasks(task); @@ -889,8 +888,12 @@ export class TerminalTaskSystem implements ITaskSystem { // There is nothing else to do here. } } - startStopProblemMatcher.done(); - startStopProblemMatcher.dispose(); + // Hack to work around #92868 until terminal is fixed. + setTimeout(() => { + onData.dispose(); + startStopProblemMatcher.done(); + startStopProblemMatcher.dispose(); + }, 100); if (!processStartedSignaled && terminal) { this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal.processId!)); processStartedSignaled = true; diff --git a/src/vs/workbench/contrib/tasks/common/problemCollectors.ts b/src/vs/workbench/contrib/tasks/common/problemCollectors.ts index 46574e02250..5e6c6f746fb 100644 --- a/src/vs/workbench/contrib/tasks/common/problemCollectors.ts +++ b/src/vs/workbench/contrib/tasks/common/problemCollectors.ts @@ -14,6 +14,7 @@ import { ILineMatcher, createLineMatcher, ProblemMatcher, ProblemMatch, ApplyToK import { IMarkerService, IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { generateUuid } from 'vs/base/common/uuid'; import { IFileService } from 'vs/platform/files/common/files'; +import { isWindows } from 'vs/base/common/platform'; export const enum ProblemCollectorEventKind { BackgroundProcessingBegins = 'backgroundProcessingBegins', @@ -282,7 +283,7 @@ export abstract class AbstractProblemCollector implements IDisposable { let existingMarker; if (!markersPerResource.has(key)) { markersPerResource.set(key, marker); - } else if (((existingMarker = markersPerResource.get(key)) !== undefined) && existingMarker.message.length < marker.message.length) { + } else if (((existingMarker = markersPerResource.get(key)) !== undefined) && (existingMarker.message.length < marker.message.length) && isWindows) { // Most likely https://github.com/microsoft/vscode/issues/77475 // Heuristic dictates that when the key is the same and message is smaller, we have hit this limitation. markersPerResource.set(key, marker); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 2a76b63a765..08dfc59ed0b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -25,7 +25,7 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager'; -import { IShellLaunchConfig, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_VIEW_ID, IWindowsShellHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource, DEFAULT_COMMANDS_TO_SKIP_SHELL, ITerminalLaunchError, IProcessDataEvent, ITerminalDimensionsOverride } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_VIEW_ID, IWindowsShellHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource, DEFAULT_COMMANDS_TO_SKIP_SHELL, ITerminalLaunchError, IProcessDataEvent, ITerminalDimensionsOverride, SHOW_TERMINAL_CONFIG_PROMPT } from 'vs/workbench/contrib/terminal/common/terminal'; import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager'; @@ -46,6 +46,7 @@ import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/e import { TerminalLaunchHelpAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { TypeAheadAddon } from 'vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon'; import { BrowserFeatures } from 'vs/base/browser/canIUse'; +import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -187,6 +188,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IKeybindingService private readonly _keybindingService: IKeybindingService, @INotificationService private readonly _notificationService: INotificationService, + @IPreferencesService private readonly _preferencesService: IPreferencesService, @IViewsService private readonly _viewsService: IViewsService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IClipboardService private readonly _clipboardService: IClipboardService, @@ -542,9 +544,29 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return false; } - // Skip processing by xterm.js of keyboard events that resolve to commands described - // within commandsToSkipShell - if (resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { + // for keyboard events that resolve to commands described + // within commandsToSkipShell, either alert or skip processing by xterm.js + if (resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId) && !this._configHelper.config.sendKeybindingsToShell) { + // don't alert when terminal is opened or closed + if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT, StorageScope.GLOBAL, true) && + resolveResult.commandId !== 'workbench.action.terminal.toggleTerminal' && + resolveResult.commandId !== 'workbench.action.terminal.new' && + resolveResult.commandId !== 'workbench.action.togglePanel' && + resolveResult.commandId !== 'workbench.action.terminal.focus') { + this._notificationService.prompt( + Severity.Info, + nls.localize('configure terminal settings', "Some keybindings are dispatched to the workbench by default."), + [ + { + label: nls.localize('configureTerminalSettings', "Configure Terminal Settings"), + run: () => { + this._preferencesService.openSettings(false, '@id:terminal.integrated.commandsToSkipShell,terminal.integrated.sendKeybindingsToShell,terminal.integrated.allowChords'); + } + } as IPromptChoice + ] + ); + this._storageService.store(SHOW_TERMINAL_CONFIG_PROMPT, false, StorageScope.GLOBAL, StorageTarget.USER); + } event.preventDefault(); return false; } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index edd076f6391..ef7ff2e50bd 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -50,7 +50,7 @@ export const KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED = new RawContextKey; } +/** + * The IncrementalChangeCollector is used in the IncrementalTestCollection + * and called with diff changes as they're applied. This is used in the + * ext host to create a cohesive change event from a diff. + */ +export class IncrementalChangeCollector { + /** + * A node was added. + */ + public add(node: T): void { } + + /** + * A node in the collection was updated. + */ + public update(node: T): void { } + + /** + * A node was removed. + */ + public remove(node: T): void { } + + /** + * Called when the diff has been applied. + */ + public complete(): void { } +} + /** * Maintains tests in this extension host sent from the main thread. */ @@ -126,19 +153,23 @@ export abstract class AbstractIncrementalTestCollection(); } /** * Creates a new item for the collection from the internal test item. */ - protected abstract createItem(internal: InternalTestItem): T; + protected abstract createItem(internal: InternalTestItem, parent?: T): T; } diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index 66ac2d3b335..465497930d7 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -302,7 +302,7 @@ class GenerateColorThemeAction extends Action { let theme = this.themeService.getColorTheme(); let colors = Registry.as(ColorRegistryExtensions.ColorContribution).getColors(); let colorIds = colors.map(c => c.id).sort(); - let resultingColors: { [key: string]: string } = {}; + let resultingColors: { [key: string]: string | null } = {}; let inherited: string[] = []; for (let colorId of colorIds) { const color = theme.getColor(colorId, false); @@ -312,12 +312,18 @@ class GenerateColorThemeAction extends Action { inherited.push(colorId); } } + const nullDefaults = []; for (let id of inherited) { const color = theme.getColor(id); if (color) { resultingColors['__' + id] = Color.Format.CSS.formatHexA(color, true); + } else { + nullDefaults.push(id); } } + for (let id of nullDefaults) { + resultingColors['__' + id] = null; + } let contents = JSON.stringify({ '$schema': colorThemeSchemaId, type: theme.type, diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index 5dae03bdd5e..3ee18c956dd 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -263,6 +263,10 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu } private onError(error: string): void { + if (/The request timed out|The network connection was lost/i.test(error)) { + return; + } + error = error.replace(/See https:\/\/github\.com\/Squirrel\/Squirrel\.Mac\/issues\/182 for more information/, 'See [this link](https://github.com/microsoft/vscode/issues/7426#issuecomment-425093469) for more information'); this.notificationService.notify({ diff --git a/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts b/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts index 25049bac517..ff54b32e0e8 100644 --- a/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts +++ b/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts @@ -36,9 +36,11 @@ export class ViewsWelcomeContribution extends Disposable implements IWorkbenchCo for (const welcome of contribution.value) { const id = ViewIdentifierMap[welcome.view] ?? welcome.view; const { group, order } = parseGroupAndOrder(welcome, contribution); + const precondition = ContextKeyExpr.deserialize(welcome.enablement); const disposable = viewsRegistry.registerViewWelcomeContent(id, { content: welcome.contents, when: ContextKeyExpr.deserialize(welcome.when), + precondition, group, order }); diff --git a/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts b/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts index ebaae9f7c68..6e19480fc91 100644 --- a/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts +++ b/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts @@ -11,6 +11,7 @@ export enum ViewsWelcomeExtensionPointFields { contents = 'contents', when = 'when', group = 'group', + enablement = 'enablement', } export interface ViewWelcome { @@ -18,6 +19,7 @@ export interface ViewWelcome { readonly [ViewsWelcomeExtensionPointFields.contents]: string; readonly [ViewsWelcomeExtensionPointFields.when]: string; readonly [ViewsWelcomeExtensionPointFields.group]: string; + readonly [ViewsWelcomeExtensionPointFields.enablement]: string; } export type ViewsWelcomeExtensionPoint = ViewWelcome[]; @@ -64,6 +66,10 @@ const viewsWelcomeExtensionPointSchema = Object.freeze this.openerService.open('https://go.microsoft.com/fwlink/?linkid=2149667') }]; - ipcRenderer.on('vscode:showShellEnvError', (event: unknown, error: string) => this.notificationService.prompt( - Severity.Error, - nls.localize('shellEnvError', "Unable to resolve your shell environment: {0}", error), - choices + ipcRenderer.on('vscode:showShellEnvSlowWarning', () => this.notificationService.prompt( + Severity.Warning, + nls.localize('shellEnvSlowWarning', "Resolving your shell environment is taking very long. Please review your shell configuration."), + choices, + { + sticky: true, + neverShowAgain: { id: 'ignoreShellEnvSlowWarning', scope: NeverShowAgainScope.GLOBAL } + } )); - ipcRenderer.on('vscode:showShellEnvTimeoutWarning', () => this.notificationService.prompt( - Severity.Warning, - nls.localize('shellEnvTimeoutWarning', "Unable to resolve your shell environment in a reasonable time. Please review your shell configuration."), + ipcRenderer.on('vscode:showShellEnvTimeoutError', () => this.notificationService.prompt( + Severity.Error, + nls.localize('shellEnvTimeoutError', "Unable to resolve your shell environment in a reasonable time. Please review your shell configuration."), choices )); @@ -296,7 +300,7 @@ export class NativeWindow extends Disposable { } // Maximize/Restore on doubleclick (for macOS custom title) - if (isMacintosh && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + if (isMacintosh && getTitleBarStyle(this.configurationService) === 'custom') { const titlePart = assertIsDefined(this.layoutService.getContainer(Parts.TITLEBAR_PART)); this._register(DOM.addDisposableListener(titlePart, DOM.EventType.DBLCLICK, e => { @@ -412,7 +416,7 @@ export class NativeWindow extends Disposable { this.customTitleContextMenuDisposable.clear(); // Provide new menu if a file is opened and we are on a custom title - if (!filePath || getTitleBarStyle(this.configurationService, this.environmentService) !== 'custom') { + if (!filePath || getTitleBarStyle(this.configurationService) !== 'custom') { return; } @@ -444,7 +448,7 @@ export class NativeWindow extends Disposable { private create(): void { // Native menu controller - if (isMacintosh || getTitleBarStyle(this.configurationService, this.environmentService) === 'native') { + if (isMacintosh || getTitleBarStyle(this.configurationService) === 'native') { this._register(this.instantiationService.createInstance(NativeMenubarControl)); } diff --git a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts index a2005fe6954..09a3e187bda 100644 --- a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts @@ -44,7 +44,7 @@ export class ContextMenuService extends Disposable implements IContextMenuServic super(); // Custom context menu: Linux/Windows if custom title is enabled - if (!isMacintosh && getTitleBarStyle(configurationService, environmentService) === 'custom') { + if (!isMacintosh && getTitleBarStyle(configurationService) === 'custom') { this.impl = new HTMLContextMenuService(telemetryService, notificationService, contextViewService, keybindingService, themeService); } diff --git a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index a9370701c61..5ef04b5f571 100644 --- a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -118,7 +118,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { ); const cache = ExtensionUrlBootstrapHandler.cache; - setTimeout(() => cache.forEach(uri => this.handleURL(uri))); + setTimeout(() => cache.forEach(([uri, option]) => this.handleURL(uri, option))); } async handleURL(uri: URI, options?: IOpenURLOptions): Promise { @@ -346,10 +346,10 @@ registerSingleton(IExtensionUrlHandler, ExtensionUrlHandler); */ class ExtensionUrlBootstrapHandler implements IWorkbenchContribution, IURLHandler { - private static _cache: URI[] = []; + private static _cache: [URI, IOpenURLOptions | undefined][] = []; private static disposable: IDisposable; - static get cache(): URI[] { + static get cache(): [URI, IOpenURLOptions | undefined][] { ExtensionUrlBootstrapHandler.disposable.dispose(); const result = ExtensionUrlBootstrapHandler._cache; @@ -361,12 +361,12 @@ class ExtensionUrlBootstrapHandler implements IWorkbenchContribution, IURLHandle ExtensionUrlBootstrapHandler.disposable = urlService.registerHandler(this); } - async handleURL(uri: URI): Promise { + async handleURL(uri: URI, options?: IOpenURLOptions): Promise { if (!isExtensionId(uri.authority)) { return false; } - ExtensionUrlBootstrapHandler._cache.push(uri); + ExtensionUrlBootstrapHandler._cache.push([uri, options]); return true; } } diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index 3050bc6e2d6..80177b1fad9 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -498,7 +498,7 @@ async function readWindowsCaCertificates() { const winCA = await import('vscode-windows-ca-certs'); let ders: any[] = []; - const store = winCA(); + const store = new winCA.Crypt32(); try { let der: any; while (der = store.next()) { diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index f4bd140d3b8..50611fa179d 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -996,7 +996,9 @@ class SettingsContentBuilder { `${displayEnum}: ${fixSettingLink(desc)}` : displayEnum; - this._contentByLines.push(`${indent}// - ${line}`); + const lines = line.split(/\n/g); + lines[0] = ' - ' + lines[0]; + this._contentByLines.push(...lines.map(l => `${indent}// ${l}`)); setting.descriptionRanges.push({ startLineNumber: this.lineCountWithOffset, startColumn: this.lastLine.indexOf(line) + 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }); }); diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index de784029338..63808d13255 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -47,51 +47,63 @@ export interface Tunnel { name?: string; description?: string; closeable?: boolean; + runningProcess: string | undefined; } -export function MakeAddress(host: string, port: number): string { +export function makeAddress(host: string, port: number): string { return host + ':' + port; } -export function mapHasTunnel(map: Map, host: string, port: number): boolean { - if (!isLocalhost(host)) { - return map.has(MakeAddress(host, port)); +export function parseAddress(address: string): { host: string, port: number } | undefined { + const matches = address.match(/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\:|localhost:)?([0-9]+)$/); + if (!matches) { + return undefined; } - - const stringAddress = MakeAddress('localhost', port); - if (map.has(stringAddress)) { - return true; - } - const numberAddress = MakeAddress('127.0.0.1', port); - if (map.has(numberAddress)) { - return true; - } - return false; + return { host: matches[1]?.substring(0, matches[1].length - 1) || 'localhost', port: Number(matches[2]) }; } -export function mapHasTunnelLocalhostOrAllInterfaces(map: Map, host: string, port: number): boolean { - if (!mapHasTunnel(map, host, port)) { - const otherHost = host === '0.0.0.0' ? 'localhost' : (host === 'localhost' ? '0.0.0.0' : undefined); - if (otherHost) { - return mapHasTunnel(map, otherHost, port); - } - return false; +export function mapHasAddress(map: Map, host: string, port: number): T | undefined { + if (!isLocalhost(host)) { + return map.get(makeAddress(host, port)); } - return true; + + const stringAddress = makeAddress('localhost', port); + if (map.has(stringAddress)) { + return map.get(stringAddress); + } + const numberAddress = makeAddress('127.0.0.1', port); + if (map.has(numberAddress)) { + return map.get(numberAddress); + } + return undefined; +} + +export function mapHasAddressLocalhostOrAllInterfaces(map: Map, host: string, port: number): T | undefined { + const originalAddress = mapHasAddress(map, host, port); + if (originalAddress) { + return originalAddress; + } + const otherHost = host === '0.0.0.0' ? 'localhost' : (host === 'localhost' ? '0.0.0.0' : undefined); + if (otherHost) { + return mapHasAddress(map, otherHost, port); + } + return undefined; } export class TunnelModel extends Disposable { readonly forwarded: Map; readonly detected: Map; + private remoteTunnels: Map; private _onForwardPort: Emitter = new Emitter(); public onForwardPort: Event = this._onForwardPort.event; private _onClosePort: Emitter<{ host: string, port: number }> = new Emitter(); public onClosePort: Event<{ host: string, port: number }> = this._onClosePort.event; private _onPortName: Emitter<{ host: string, port: number }> = new Emitter(); public onPortName: Event<{ host: string, port: number }> = this._onPortName.event; - private _candidates: { host: string, port: number, detail: string }[] = []; - private _onCandidatesChanged: Emitter = new Emitter(); - public onCandidatesChanged: Event = this._onCandidatesChanged.event; + private _candidates: Map; + private _onCandidatesChanged: Emitter> = new Emitter(); + // onCandidateChanged returns the removed candidates + public onCandidatesChanged: Event> = this._onCandidatesChanged.event; private _candidateFilter: ((candidates: { host: string, port: number, detail: string }[]) => Promise<{ host: string, port: number, detail: string }[]>) | undefined; constructor( @@ -102,37 +114,44 @@ export class TunnelModel extends Disposable { @IRemoteAuthorityResolverService private readonly remoteAuthorityResolverService: IRemoteAuthorityResolverService, ) { super(); + this._candidates = new Map(); this.forwarded = new Map(); + this.remoteTunnels = new Map(); this.tunnelService.tunnels.then(tunnels => { tunnels.forEach(tunnel => { if (tunnel.localAddress) { - this.forwarded.set(MakeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort), { + const key = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); + this.forwarded.set(key, { remotePort: tunnel.tunnelRemotePort, remoteHost: tunnel.tunnelRemoteHost, localAddress: tunnel.localAddress, - localPort: tunnel.tunnelLocalPort + localPort: tunnel.tunnelLocalPort, + runningProcess: mapHasAddressLocalhostOrAllInterfaces(this._candidates, tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort)?.detail }); + this.remoteTunnels.set(key, tunnel); } }); }); this.detected = new Map(); this._register(this.tunnelService.onTunnelOpened(tunnel => { - const key = MakeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); + const key = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); if ((!this.forwarded.has(key)) && tunnel.localAddress) { this.forwarded.set(key, { remoteHost: tunnel.tunnelRemoteHost, remotePort: tunnel.tunnelRemotePort, localAddress: tunnel.localAddress, localPort: tunnel.tunnelLocalPort, - closeable: true + closeable: true, + runningProcess: mapHasAddressLocalhostOrAllInterfaces(this._candidates, tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort)?.detail }); this.storeForwarded(); } + this.remoteTunnels.set(key, tunnel); this._onForwardPort.fire(this.forwarded.get(key)!); })); this._register(this.tunnelService.onTunnelClosed(address => { - const key = MakeAddress(address.host, address.port); + const key = makeAddress(address.host, address.port); if (this.forwarded.has(key)) { this.forwarded.delete(key); this.storeForwarded(); @@ -159,8 +178,8 @@ export class TunnelModel extends Disposable { } async forward(remote: { host: string, port: number }, local?: number, name?: string): Promise { - const key = MakeAddress(remote.host, remote.port); - if (!this.forwarded.has(key)) { + const existingTunnel = mapHasAddressLocalhostOrAllInterfaces(this.forwarded, remote.host, remote.port); + if (!existingTunnel) { const authority = this.environmentService.remoteAuthority; const addressProvider: IAddressProvider | undefined = authority ? { getAddress: async () => { return (await this.remoteAuthorityResolverService.resolveAuthority(authority)).authority; } @@ -174,17 +193,24 @@ export class TunnelModel extends Disposable { localPort: tunnel.tunnelLocalPort, name: name, closeable: true, - localAddress: tunnel.localAddress + localAddress: tunnel.localAddress, + runningProcess: mapHasAddressLocalhostOrAllInterfaces(this._candidates, remote.host, remote.port)?.detail }; + const key = makeAddress(remote.host, remote.port); this.forwarded.set(key, newForward); + this.remoteTunnels.set(key, tunnel); this._onForwardPort.fire(newForward); return tunnel; } + } else { + existingTunnel.name = name; + this._onForwardPort.fire(); + return mapHasAddressLocalhostOrAllInterfaces(this.remoteTunnels, remote.host, remote.port); } } name(host: string, port: number, name: string) { - const key = MakeAddress(host, port); + const key = makeAddress(host, port); if (this.forwarded.has(key)) { this.forwarded.get(key)!.name = name; this.storeForwarded(); @@ -200,17 +226,18 @@ export class TunnelModel extends Disposable { } address(host: string, port: number): string | undefined { - const key = MakeAddress(host, port); + const key = makeAddress(host, port); return (this.forwarded.get(key) || this.detected.get(key))?.localAddress; } addEnvironmentTunnels(tunnels: TunnelDescription[]): void { tunnels.forEach(tunnel => { - this.detected.set(MakeAddress(tunnel.remoteAddress.host, tunnel.remoteAddress.port), { + this.detected.set(makeAddress(tunnel.remoteAddress.host, tunnel.remoteAddress.port), { remoteHost: tunnel.remoteAddress.host, remotePort: tunnel.remoteAddress.port, - localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : MakeAddress(tunnel.localAddress.host, tunnel.localAddress.port), - closeable: false + localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : makeAddress(tunnel.localAddress.host, tunnel.localAddress.port), + closeable: false, + runningProcess: mapHasAddressLocalhostOrAllInterfaces(this._candidates, tunnel.remoteAddress.host, tunnel.remoteAddress.port)?.detail }); }); this._onForwardPort.fire(); @@ -223,22 +250,58 @@ export class TunnelModel extends Disposable { async setCandidates(candidates: { host: string, port: number, detail: string }[]) { let processedCandidates = candidates; if (this._candidateFilter) { + // When an extension provides a filter, we do the filtering on the extension host before the candidates are set here. + // However, when the filter doesn't come from an extension we filter here. processedCandidates = await this._candidateFilter(candidates); } - this._candidates = processedCandidates.map(value => { - const nullIndex = value.detail.indexOf('\0'); - const detail = value.detail.substr(0, nullIndex > 0 ? nullIndex : value.detail.length).trim(); - return { + const removedCandidates = this.updateInResponseToCandidates(processedCandidates); + this._onCandidatesChanged.fire(removedCandidates); + } + + private polishProcessDetail(detail: string): string { + const nullIndex = detail.indexOf('\0'); + return detail.substr(0, nullIndex > 0 ? nullIndex : detail.length).trim(); + } + + // Returns removed candidates + private updateInResponseToCandidates(candidates: { host: string, port: number, detail: string }[]): Map { + const removedCandidates = this._candidates; + this._candidates = new Map(); + candidates.forEach(value => { + const detail = this.polishProcessDetail(value.detail); + const addressKey = makeAddress(value.host, value.port); + this._candidates.set(addressKey, { host: value.host, port: value.port, detail - }; + }); + if (removedCandidates.has(addressKey)) { + removedCandidates.delete(addressKey); + } + const forwardedValue = mapHasAddressLocalhostOrAllInterfaces(this.forwarded, value.host, value.port); + if (forwardedValue) { + forwardedValue.runningProcess = detail; + } }); - this._onCandidatesChanged.fire(); + removedCandidates.forEach((_value, key) => { + const parsedAddress = parseAddress(key); + if (!parsedAddress) { + return; + } + const forwardedValue = mapHasAddressLocalhostOrAllInterfaces(this.forwarded, parsedAddress.host, parsedAddress.port); + if (forwardedValue) { + forwardedValue.runningProcess = undefined; + } + const detectedValue = mapHasAddressLocalhostOrAllInterfaces(this.detected, parsedAddress.host, parsedAddress.port); + if (detectedValue) { + detectedValue.runningProcess = undefined; + } + }); + return removedCandidates; } get candidates(): { host: string, port: number, detail: string }[] { - return this._candidates; + return Array.from(this._candidates.values()); } } diff --git a/src/vs/workbench/services/timer/browser/timerService.ts b/src/vs/workbench/services/timer/browser/timerService.ts index b63386aa9f2..2f146375db0 100644 --- a/src/vs/workbench/services/timer/browser/timerService.ts +++ b/src/vs/workbench/services/timer/browser/timerService.ts @@ -193,7 +193,7 @@ export interface IStartupMetrics { * * Happens in the renderer-process * * Measured with the `willWaitForShellEnv` and `didWaitForShellEnv` performance marks. */ - readonly ellapsedWaitForShellEnv?: number; + readonly ellapsedWaitForShellEnv: number; /** * The time it took to require the workspace storage DB, connect to it diff --git a/src/vs/workbench/test/browser/api/extHostTesting.test.ts b/src/vs/workbench/test/browser/api/extHostTesting.test.ts index 2c784c043d8..9ed0f4b2557 100644 --- a/src/vs/workbench/test/browser/api/extHostTesting.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTesting.test.ts @@ -8,7 +8,89 @@ import { MirroredTestCollection, OwnedTestCollection, SingleUseTestCollection } import * as convert from 'vs/workbench/api/common/extHostTypeConverters'; import { TestRunState, TestState } from 'vs/workbench/api/common/extHostTypes'; import { TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; -import { TestItem } from 'vscode'; +import { TestChangeEvent, TestItem } from 'vscode'; + +const stubTest = (label: string): TestItem => ({ + label, + location: undefined, + state: new TestState(TestRunState.Unset), + debuggable: true, + runnable: true, + description: '' +}); + +const simplify = (item: TestItem) => { + if ('toJSON' in item) { + item = (item as any).toJSON(); + } + + return { ...item, children: undefined }; +}; + +const assertTreesEqual = (a: Readonly, b: Readonly) => { + assert.deepStrictEqual(simplify(a), simplify(b)); + + const aChildren = (a.children ?? []).sort(); + const bChildren = (b.children ?? []).sort(); + assert.strictEqual(aChildren.length, bChildren.length, `expected ${a.label}.children.length == ${b.label}.children.length`); + aChildren.forEach((_, i) => assertTreesEqual(aChildren[i], bChildren[i])); +}; + +const assertTreeListEqual = (a: ReadonlyArray>, b: ReadonlyArray>) => { + assert.strictEqual(a.length, b.length, `expected a.length == n.length`); + a.forEach((_, i) => assertTreesEqual(a[i], b[i])); +}; + +const stubNestedTests = () => ({ + ...stubTest('root'), + children: [ + { ...stubTest('a'), children: [stubTest('aa'), stubTest('ab')] }, + stubTest('b'), + ] +}); + +class TestOwnedTestCollection extends OwnedTestCollection { + public get idToInternal() { + return this.testIdToInternal; + } + + public createForHierarchy(publishDiff: (diff: TestsDiff) => void = () => undefined) { + return new TestSingleUseCollection(this.testIdToInternal, publishDiff); + } +} + +class TestSingleUseCollection extends SingleUseTestCollection { + private idCounter = 0; + + public get itemToInternal() { + return this.testItemToInternal; + } + + public get currentDiff() { + return this.diff; + } + + protected getId() { + return String(this.idCounter++); + } + + public setDiff(diff: TestsDiff) { + this.diff = diff; + } +} + +class TestMirroredCollection extends MirroredTestCollection { + public changeEvent!: TestChangeEvent; + + constructor() { + super(); + this.onDidChangeTests(evt => this.changeEvent = evt); + } + + public get length() { + return this.items.size; + } +} suite('ExtHost Testing', () => { let single: TestSingleUseCollection; @@ -88,8 +170,10 @@ suite('ExtHost Testing', () => { }); suite('MirroredTestCollection', () => { + let m: TestMirroredCollection; + setup(() => m = new TestMirroredCollection()); + test('mirrors creation of the root', () => { - const m = new TestMirroredCollection(); const tests = stubNestedTests(); single.addRoot(tests, 'pid'); m.apply(single.collectDiff()); @@ -98,7 +182,6 @@ suite('ExtHost Testing', () => { }); test('mirrors node deletion', () => { - const m = new TestMirroredCollection(); const tests = stubNestedTests(); single.addRoot(tests, 'pid'); m.apply(single.collectDiff()); @@ -111,7 +194,6 @@ suite('ExtHost Testing', () => { }); test('mirrors node addition', () => { - const m = new TestMirroredCollection(); const tests = stubNestedTests(); single.addRoot(tests, 'pid'); m.apply(single.collectDiff()); @@ -124,7 +206,6 @@ suite('ExtHost Testing', () => { }); test('mirrors node update', () => { - const m = new TestMirroredCollection(); const tests = stubNestedTests(); single.addRoot(tests, 'pid'); m.apply(single.collectDiff()); @@ -134,67 +215,96 @@ suite('ExtHost Testing', () => { assertTreesEqual(m.rootTestItems[0], owned.getTestById('0')!.actual); }); + + suite('MirroredChangeCollector', () => { + let tests = stubNestedTests(); + setup(() => { + tests = stubNestedTests(); + single.addRoot(tests, 'pid'); + m.apply(single.collectDiff()); + }); + + test('creates change for root', () => { + assert.deepStrictEqual(m.changeEvent.commonChangeAncestor, null); + assertTreeListEqual(m.changeEvent.added, [ + tests, + tests.children[0], + tests.children![0].children![0], + tests.children![0].children![1], + tests.children[1], + ]); + assertTreeListEqual(m.changeEvent.removed, []); + assertTreeListEqual(m.changeEvent.updated, []); + }); + + test('creates change for delete', () => { + const rm = tests.children.shift()!; + single.onItemChange(tests, 'pid'); + m.apply(single.collectDiff()); + + assertTreesEqual(m.changeEvent.commonChangeAncestor!, tests); + assertTreeListEqual(m.changeEvent.added, []); + assertTreeListEqual(m.changeEvent.removed, [ + { ...rm, children: [] }, + { ...rm.children![0], children: [] }, + { ...rm.children![1], children: [] }, + ]); + assertTreeListEqual(m.changeEvent.updated, []); + }); + + test('creates change for update', () => { + tests.children[0].label = 'updated!'; + single.onItemChange(tests, 'pid'); + m.apply(single.collectDiff()); + + assert.deepStrictEqual(m.changeEvent.commonChangeAncestor?.label, 'updated!'); + assertTreeListEqual(m.changeEvent.added, []); + assertTreeListEqual(m.changeEvent.removed, []); + assertTreeListEqual(m.changeEvent.updated, [tests.children[0]]); + }); + + test('is a no-op if a node is added and removed', () => { + const nested = stubNestedTests(); + tests.children.push(nested); + single.onItemChange(tests, 'pid'); + tests.children.pop(); + single.onItemChange(tests, 'pid'); + const previousEvent = m.changeEvent; + m.apply(single.collectDiff()); + assert.strictEqual(m.changeEvent, previousEvent); + }); + + test('is a single-op if a node is added and changed', () => { + const child = stubTest('c'); + tests.children.push(child); + single.onItemChange(tests, 'pid'); + child.label = 'd'; + single.onItemChange(tests, 'pid'); + m.apply(single.collectDiff()); + + assert.strictEqual(m.changeEvent.commonChangeAncestor?.label, 'root'); + assertTreeListEqual(m.changeEvent.added, [child]); + assertTreeListEqual(m.changeEvent.removed, []); + assertTreeListEqual(m.changeEvent.updated, []); + }); + + test('gets the common ancestor (1)', () => { + tests.children![0].children![0].label = 'za'; + tests.children![0].children![1].label = 'zb'; + single.onItemChange(tests, 'pid'); + m.apply(single.collectDiff()); + + assert.strictEqual(m.changeEvent.commonChangeAncestor?.label, 'a'); + }); + + test('gets the common ancestor (2)', () => { + tests.children![0].children![0].label = 'za'; + tests.children![1].label = 'ab'; + single.onItemChange(tests, 'pid'); + m.apply(single.collectDiff()); + + assert.strictEqual(m.changeEvent.commonChangeAncestor?.label, 'root'); + }); + }); }); }); - -const stubTest = (label: string): TestItem => ({ - label, - location: undefined, - state: new TestState(TestRunState.Unset), - debuggable: true, - runnable: true, - description: '' -}); - -const assertTreesEqual = (a: TestItem, b: TestItem) => { - assert.deepStrictEqual({ ...a, children: undefined }, { ...b, children: undefined }); - - const aChildren = (a.children ?? []).sort(); - const bChildren = (b.children ?? []).sort(); - assert.strictEqual(aChildren.length, bChildren.length, `expected ${a.label}.children.length == ${b.label}.children.length`); - aChildren.forEach((_, i) => assertTreesEqual(aChildren[i], bChildren[i])); -}; - -const stubNestedTests = () => ({ - ...stubTest('root'), - children: [ - { ...stubTest('a'), children: [stubTest('aa'), stubTest('ab')] }, - stubTest('b'), - ] -}); - -class TestOwnedTestCollection extends OwnedTestCollection { - public get idToInternal() { - return this.testIdToInternal; - } - - public createForHierarchy(publishDiff: (diff: TestsDiff) => void = () => undefined) { - return new TestSingleUseCollection(this.testIdToInternal, publishDiff); - } -} - -class TestSingleUseCollection extends SingleUseTestCollection { - private idCounter = 0; - - public get itemToInternal() { - return this.testItemToInternal; - } - - public get currentDiff() { - return this.diff; - } - - protected getId() { - return String(this.idCounter++); - } - - public setDiff(diff: TestsDiff) { - this.diff = diff; - } -} - -class TestMirroredCollection extends MirroredTestCollection { - public get length() { - return this.items.size; - } -} diff --git a/yarn.lock b/yarn.lock index a3f05fe9cb8..44086114c87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -160,6 +160,13 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== +"@malept/cross-spawn-promise@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.0.tgz#258fde4098f5004a56db67c35f33033af64810f6" + integrity sha512-GeIK5rfU1Yd7BZJQPTGZMMmcZy5nhRToPXZcjaDwQDRSewdhp648GT2E4dh+L7+Io7AOW6WQ+GR44QSzja4qxg== + dependencies: + cross-spawn "^7.0.1" + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -186,6 +193,11 @@ dependencies: chokidar "*" +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + "@types/commander@^2.11.0": version "2.12.2" resolved "https://registry.yarnpkg.com/@types/commander/-/commander-2.12.2.tgz#183041a23842d4281478fa5d23c5ca78e6fd08ae" @@ -696,6 +708,16 @@ ajv@^6.10.0, ajv@^6.10.2: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.3: + version "6.12.4" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" + integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ajv@^6.5.3, ajv@^6.6.1: version "6.8.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.8.1.tgz#0890b93742985ebf8973cd365c5b23920ce3cb20" @@ -805,6 +827,14 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + ansi-wrap@0.1.0, ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -1104,6 +1134,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" @@ -1605,6 +1640,14 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -1720,6 +1763,11 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + chrome-remote-interface@0.26.1: version "0.26.1" resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.26.1.tgz#6c7d4479742b6d236752d716a9bc2d322d7d8ad2" @@ -1789,6 +1837,11 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" +cli-spinners@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.4.0.tgz#c6256db216b878cfba4720e719cec7cf72685d7f" + integrity sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA== + cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -1812,6 +1865,15 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" +cliui@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.1.tgz#a4cb67aad45cd83d8d05128fc9f4d8fbb887e6b3" + integrity sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" @@ -1908,11 +1970,23 @@ color-convert@^1.3.0, color-convert@^1.9.0: dependencies: color-name "^1.1.1" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@^1.0.0, color-name@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + color-string@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" @@ -1948,6 +2022,11 @@ colors@^1.1.2: resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.1.tgz#f4a3d302976aaf042356ba1ade3b1a2c62d9d794" integrity sha512-s8+wktIuDSLffCywiwSxQOMqtPxML11a/dtHE17tMn4B1MSWw/C22EKf7M2KGUBcDaVFEGT+S8N02geDXeuNKg== +colors@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -2209,6 +2288,15 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + crypt@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" @@ -2474,6 +2562,13 @@ default-resolution@^2.0.0: resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684" integrity sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ= +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + defer-to-connect@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.1.tgz#88ae694b93f67b81815a2c8c769aef6574ac8f2f" @@ -2742,15 +2837,30 @@ editorconfig@^0.15.2: semver "^5.6.0" sigmund "^1.0.1" +electron-rebuild@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-2.0.3.tgz#fbcf34d35bf6795a0ded39bfe2aee24526a152c8" + integrity sha512-I8Oeey9afU+trFLd8/qRRiHC083CCoBnmw3q0qQaRFsg0OzMaeJQn7Nl6EYKPpntuQ/3yOqZQ7b3ObNuETN/Ig== + dependencies: + "@malept/cross-spawn-promise" "^1.1.0" + colors "^1.3.3" + debug "^4.1.1" + detect-libc "^1.0.3" + fs-extra "^9.0.1" + node-abi "^2.19.1" + node-gyp "^7.1.0" + ora "^5.1.0" + yargs "^16.0.0" + electron-to-chromium@^1.2.7: version "1.3.27" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz#78ecb8a399066187bb374eede35d9c70565a803d" integrity sha1-eOy4o5kGYYe7N07t412ccFZagD0= -electron@9.3.3: - version "9.3.3" - resolved "https://registry.yarnpkg.com/electron/-/electron-9.3.3.tgz#99a6619d5df68f97697a5d1d82ef3a8a63fcdf36" - integrity sha512-xghKeUY1qgnEcJ5w2rXo/toH+8NT2Dktx2aAxBNPV7CIJr3mejJJAPwLbycwtddzr37tgKxHeHlc8ivfKtMkJQ== +electron@11.0.2: + version "11.0.2" + resolved "https://registry.yarnpkg.com/electron/-/electron-11.0.2.tgz#c7bd2b9abdc1446f4578dbfa22573014b6b2df58" + integrity sha512-FTYtCm0oj8B8EJhp99BQSW2bd40xYEG/txMj+W3Ed0CNu5zVIIXb5WIrhXLvhcasN5LKy9nkmSZ+u220lCaARg== dependencies: "@electron/get" "^1.0.1" "@types/node" "^12.0.12" @@ -2916,6 +3026,11 @@ es6-weak-map@^2.0.1: es6-iterator "^2.0.1" es6-symbol "^3.1.1" +escalade@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4" + integrity sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ== + 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" @@ -3359,6 +3474,11 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -3688,6 +3808,16 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" + integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^1.0.0" + fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -3695,6 +3825,13 @@ fs-minipass@^1.2.5: dependencies: minipass "^2.2.1" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs-mkdirp-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb" @@ -3780,7 +3917,7 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" integrity sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U= -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -4094,7 +4231,7 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= -graceful-fs@^4.1.15: +graceful-fs@^4.1.15, graceful-fs@^4.2.3: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -4380,6 +4517,14 @@ har-validator@~5.1.0: ajv "^5.3.0" har-schema "^2.0.0" +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -4976,6 +5121,11 @@ is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + is-negated-glob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" @@ -5383,6 +5533,15 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179" + integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg== + dependencies: + universalify "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -5648,6 +5807,13 @@ lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17. resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== +log-symbols@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" + integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== + dependencies: + chalk "^4.0.0" + lolex@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31" @@ -6011,6 +6177,13 @@ minipass@^2.2.1, minipass@^2.3.3: safe-buffer "^5.1.2" yallist "^3.0.0" +minipass@^3.0.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" + integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== + dependencies: + yallist "^4.0.0" + minizlib@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" @@ -6018,6 +6191,14 @@ minizlib@^1.1.0: dependencies: minipass "^2.2.1" +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mississippi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" @@ -6082,6 +6263,11 @@ mkdirp@^0.5.3: dependencies: minimist "^1.2.5" +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mocha-junit-reporter@^1.17.0: version "1.17.0" resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.17.0.tgz#2e5149ed40fc5d2e3ca71e42db5ab1fec9c6d85c" @@ -6161,7 +6347,12 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.10.0, nan@^2.13.2, nan@^2.14.0: +nan@^2.10.0: + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + +nan@^2.13.2, nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -6237,23 +6428,34 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" integrity sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA== -node-abi@^2.7.0: +node-abi@^2.19.1, node-abi@^2.7.0: version "2.19.3" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.19.3.tgz#252f5dcab12dad1b5503b2d27eddd4733930282d" integrity sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg== dependencies: semver "^5.4.1" -node-addon-api@1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217" - integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA== - -node-addon-api@^3.0.0: +node-addon-api@^3.0.0, node-addon-api@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.2.tgz#04bc7b83fd845ba785bb6eae25bc857e1ef75681" integrity sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg== +node-gyp@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.0.tgz#cb8aed7ab772e73ad592ae0c71b0e3741099fe39" + integrity sha512-rjlHQlnl1dqiDZxZYiKqQdrjias7V+81OVR5PTzZioCBtWkNdrKy06M05HLKxy/pcKikKRCabeDRoZaEc6nIjw== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.3" + nopt "^4.0.3" + npmlog "^4.1.2" + request "^2.88.2" + rimraf "^2.6.3" + semver "^7.3.2" + tar "^6.0.1" + which "^2.0.2" + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -6299,10 +6501,10 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-pty@0.10.0-beta17: - version "0.10.0-beta17" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta17.tgz#962d4a3f4dc6772385e0cad529c209cef3bc79e6" - integrity sha512-tn7EANQacnAvnOQCImvgag1DL0tVmUoY/1yIZbh3u/BBpvCcGHLZJNn7TXheodRLr6hmGSUS2VbfcUr9p0gOug== +node-pty@0.10.0-beta18: + version "0.10.0-beta18" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta18.tgz#7ed2d3f4a06b2b23fe2abdf5b41655e9dffc25d5" + integrity sha512-vpK4yB3A3VzgkvdOWegL7GcPapt45jfA4b3ejUe8k4RmqdWBRvFJngew8T3qAxmLhTkfo93psaN6izTlfkc6FA== dependencies: nan "^2.14.0" @@ -6327,6 +6529,14 @@ nopt@^4.0.1, nopt@~4.0.1: abbrev "1" osenv "^0.1.4" +nopt@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" + normalize-package-data@^2.3.2: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" @@ -6414,7 +6624,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npmlog@^4.0.1, npmlog@^4.0.2: +npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -6610,6 +6820,20 @@ optionator@^0.8.3: type-check "~0.3.2" word-wrap "~1.2.3" +ora@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.1.0.tgz#b188cf8cd2d4d9b13fd25383bc3e5cba352c94f8" + integrity sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w== + dependencies: + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.4.0" + is-interactive "^1.0.0" + log-symbols "^4.0.0" + mute-stream "0.0.8" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + ordered-read-streams@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b" @@ -6886,6 +7110,11 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" @@ -7464,6 +7693,11 @@ psl@^1.1.24: resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" integrity sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ== +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + public-encrypt@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" @@ -7518,7 +7752,7 @@ punycode@^1.2.4, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -7934,6 +8168,32 @@ request@^2.86.0, request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +request@^2.88.2: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + requestretry@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-4.0.0.tgz#4e9e7280a7d8561bf33e9925264cf026e2be3e89" @@ -8316,11 +8576,23 @@ shebang-command@^1.2.0: dependencies: shebang-regex "^1.0.0" +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.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= +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + shimmer@^1.1.0, shimmer@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" @@ -8712,7 +8984,7 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0: +string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== @@ -8983,6 +9255,18 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" +tar@^6.0.1: + version "6.0.5" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" + integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + tas-client-umd@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/tas-client-umd/-/tas-client-umd-0.1.2.tgz#fe93ae085f65424292ac79feff4f1add3e50e624" @@ -9190,6 +9474,14 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -9402,6 +9694,11 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" + integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -9765,12 +10062,12 @@ vscode-textmate@5.2.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== -vscode-windows-ca-certs@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.2.0.tgz#086f0f4de57e2760a35ac6920831bff246237115" - integrity sha512-YBrJRT0zos+Yb1Qdn73GD8QZr7pa2IE96b5Y1hmmp6XeR8aYB7Iiq5gDAF/+/AxL+caSR9KPZQ6jiYWh5biD7w== +vscode-windows-ca-certs@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.3.0.tgz#324e1f8ba842bbf048a39e7c0ee8fe655e9adfcc" + integrity sha512-CYrpCEKmAFQJoZNReOrelNL+VKyebOVRCqL9evrBlVcpWQDliliJgU5RggGS8FPGtQ3jAKLQt9frF0qlxYYPKA== dependencies: - node-addon-api "1.6.2" + node-addon-api "^3.0.2" vscode-windows-registry@1.0.3: version "1.0.3" @@ -9805,6 +10102,13 @@ watchpack@^1.6.1: chokidar "^3.4.0" watchpack-chokidar2 "^2.0.0" +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + webpack-cli@^3.3.12: version "3.3.12" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a" @@ -9913,6 +10217,13 @@ which@^1.2.9: dependencies: isexe "^2.0.0" +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -9979,6 +10290,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -10101,6 +10421,11 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +y18n@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.1.tgz#1ad2a7eddfa8bce7caa2e1f6b5da96c39d99d571" + integrity sha512-/jJ831jEs4vGDbYPQp4yGKDYPSCCEQ45uZWJHE1AoYBzqdZi8+LDWas0z4HrmJXmKdpFsTiowSHXdxyFhpmdMg== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -10111,6 +10436,11 @@ yallist@^3.0.0, yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k= +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yargs-parser@^13.1.0: version "13.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" @@ -10127,6 +10457,11 @@ yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^20.0.0: + version "20.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.0.0.tgz#c65a1daaa977ad63cebdd52159147b789a4e19a9" + integrity sha512-8eblPHTL7ZWRkyjIZJjnGf+TijiKJSwA24svzLRVvtgoi/RZiKa9fFQTrlx0OKLnyHSdt/enrdadji6WFfESVA== + yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" @@ -10167,6 +10502,19 @@ yargs@^13.3.0, yargs@^13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" +yargs@^16.0.0: + version "16.0.3" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.0.3.tgz#7a919b9e43c90f80d4a142a89795e85399a7e54c" + integrity sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA== + dependencies: + cliui "^7.0.0" + escalade "^3.0.2" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.1" + yargs-parser "^20.0.0" + yargs@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"