mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
49dc593a83
13
.github/commands.json
vendored
13
.github/commands.json
vendored
|
@ -202,6 +202,19 @@
|
|||
"addLabel": "*caused-by-extension",
|
||||
"comment": "It looks like this is caused by the Python extension. Please file it with the repository [here](https://github.com/microsoft/vscode-python). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "extJupyter",
|
||||
"allowUsers": [
|
||||
"cleidigh",
|
||||
"usernamehw",
|
||||
"gjsjohnmurray",
|
||||
"IllusionMH"
|
||||
],
|
||||
"action": "close",
|
||||
"addLabel": "*caused-by-extension",
|
||||
"comment": "It looks like this is caused by the Jupyter extension. Please file it with the repository [here](https://github.com/microsoft/vscode-jupyter). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "extC",
|
||||
|
|
2
.github/workflows/author-verified.yml
vendored
2
.github/workflows/author-verified.yml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v40
|
||||
ref: v41
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'author-verification-requested')
|
||||
|
|
2
.github/workflows/commands.yml
vendored
2
.github/workflows/commands.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v40
|
||||
ref: v41
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run Commands
|
||||
|
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v40
|
||||
ref: v41
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
2
.github/workflows/deep-classifier-runner.yml
vendored
2
.github/workflows/deep-classifier-runner.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v40
|
||||
ref: v41
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v40
|
||||
ref: v41
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
2
.github/workflows/english-please.yml
vendored
2
.github/workflows/english-please.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v40
|
||||
ref: v41
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
if: contains(github.event.issue.labels.*.name, '*english-please')
|
||||
|
|
2
.github/workflows/feature-request.yml
vendored
2
.github/workflows/feature-request.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v40
|
||||
ref: v41
|
||||
- name: Install Actions
|
||||
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request')
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
2
.github/workflows/latest-release-monitor.yml
vendored
2
.github/workflows/latest-release-monitor.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v40
|
||||
ref: v41
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Install Storage Module
|
||||
|
|
2
.github/workflows/locker.yml
vendored
2
.github/workflows/locker.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v40
|
||||
ref: v41
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run Locker
|
||||
|
|
2
.github/workflows/needs-more-info-closer.yml
vendored
2
.github/workflows/needs-more-info-closer.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v40
|
||||
ref: v41
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run Needs More Info Closer
|
||||
|
|
2
.github/workflows/on-label.yml
vendored
2
.github/workflows/on-label.yml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v40
|
||||
ref: v41
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
2
.github/workflows/on-open.yml
vendored
2
.github/workflows/on-open.yml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v40
|
||||
ref: v41
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v40
|
||||
ref: v41
|
||||
path: ./actions
|
||||
- name: Checkout Repo
|
||||
if: github.event_name != 'issues'
|
||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v40
|
||||
ref: v41
|
||||
- name: Install Actions
|
||||
if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item')
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
2
.vscode/notebooks/endgame.github-issues
vendored
2
.vscode/notebooks/endgame.github-issues
vendored
|
@ -104,7 +104,7 @@
|
|||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$REPOS $MILESTONE label:candidate",
|
||||
"value": "$REPOS $MILESTONE is:open label:candidate",
|
||||
"editable": true
|
||||
}
|
||||
]
|
14
.vscode/notebooks/my-endgame.github-issues
vendored
14
.vscode/notebooks/my-endgame.github-issues
vendored
|
@ -122,7 +122,7 @@
|
|||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$REPOS $MILESTONE $MINE is:issue is:open",
|
||||
"value": "$REPOS $MILESTONE $MINE is:issue is:open -label:endgame-plan",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
|
@ -179,6 +179,18 @@
|
|||
"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 from outside team",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$REPOS $MILESTONE -$MINE 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 -author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:bamurtaugh -author:bpasero -author:btholt -author:chrisdias -author:chrmarti -author:Chuxel -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:eamodio -author:egamma -author:fiveisprime -author:gregvanl -author:isidorn -author:ItalyPaleAle -author:JacksonKearl -author:joaomoreno -author:jrieken -author:kieferrm -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:ornellaalt -author:orta -author:rebornix -author:RMacfarlane -author:roblourens -author:rzhao271 -author:sana-ajani -author:sandy081 -author:sbatten -author:stevencl -author:Tyriar -author:weinand",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
|
|
2
.vscode/notebooks/verification.github-issues
vendored
2
.vscode/notebooks/verification.github-issues
vendored
|
@ -14,7 +14,7 @@
|
|||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks \n$milestone=milestone:\"October 2020\"",
|
||||
"value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks \n$milestone=milestone:\"November 2020\"",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
|
|
2
.yarnrc
2
.yarnrc
|
@ -1,3 +1,3 @@
|
|||
disturl "https://electronjs.org/headers"
|
||||
target "9.3.5"
|
||||
target "11.0.3"
|
||||
runtime "electron"
|
||||
|
|
|
@ -66,7 +66,7 @@ This project incorporates components from the projects listed below. The origina
|
|||
59. vscode-codicons version 0.0.1 (https://github.com/microsoft/vscode-codicons)
|
||||
60. vscode-logfile-highlighter version 2.8.0 (https://github.com/emilast/vscode-logfile-highlighter)
|
||||
61. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift)
|
||||
62. Web Background Synchronization (https://github.com/WICG/BackgroundSync)
|
||||
62. Web Background Synchronization (https://github.com/WICG/background-sync)
|
||||
|
||||
|
||||
%% atom/language-clojure NOTICES AND INFORMATION BEGIN HERE
|
||||
|
|
|
@ -16,3 +16,8 @@ jobs:
|
|||
vmImage: macOS-latest
|
||||
steps:
|
||||
- template: build/azure-pipelines/darwin/continuous-build-darwin.yml
|
||||
|
||||
trigger:
|
||||
branches:
|
||||
exclude:
|
||||
- electron-11.x.y
|
||||
|
|
|
@ -1 +1 @@
|
|||
2020-11-30T16:21:34.566Z
|
||||
2020-12-05T15:02:48.675Z
|
||||
|
|
|
@ -11,6 +11,7 @@ import * as crypto from 'crypto';
|
|||
import * as azure from 'azure-storage';
|
||||
import * as mime from 'mime';
|
||||
import { CosmosClient } from '@azure/cosmos';
|
||||
import { retry } from './retry';
|
||||
|
||||
interface Asset {
|
||||
platform: string;
|
||||
|
@ -121,7 +122,7 @@ async function main(): Promise<void> {
|
|||
|
||||
const client = new CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT']!, key: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
|
||||
const scripts = client.database('builds').container(quality).scripts;
|
||||
await scripts.storedProcedure('createAsset').execute('', [commit, asset, true]);
|
||||
await retry(() => scripts.storedProcedure('createAsset').execute('', [commit, asset, true]));
|
||||
}
|
||||
|
||||
main().then(() => {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
'use strict';
|
||||
|
||||
import { CosmosClient } from '@azure/cosmos';
|
||||
import { retry } from './retry';
|
||||
|
||||
if (process.argv.length !== 3) {
|
||||
console.error('Usage: node createBuild.js VERSION');
|
||||
|
@ -48,7 +49,7 @@ async function main(): Promise<void> {
|
|||
|
||||
const client = new CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT']!, key: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
|
||||
const scripts = client.database('builds').container(quality).scripts;
|
||||
await scripts.storedProcedure('createBuild').execute('', [{ ...build, _partitionKey: '' }]);
|
||||
await retry(() => scripts.storedProcedure('createBuild').execute('', [{ ...build, _partitionKey: '' }]));
|
||||
}
|
||||
|
||||
main().then(() => {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
'use strict';
|
||||
|
||||
import { CosmosClient } from '@azure/cosmos';
|
||||
import { retry } from './retry';
|
||||
|
||||
function getEnv(name: string): string {
|
||||
const result = process.env[name];
|
||||
|
@ -58,7 +59,7 @@ async function main(): Promise<void> {
|
|||
console.log(`Releasing build ${commit}...`);
|
||||
|
||||
const scripts = client.database('builds').container(quality).scripts;
|
||||
await scripts.storedProcedure('releaseBuild').execute('', [commit]);
|
||||
await retry(() => scripts.storedProcedure('releaseBuild').execute('', [commit]));
|
||||
}
|
||||
|
||||
main().then(() => {
|
||||
|
|
26
build/azure-pipelines/common/retry.ts
Normal file
26
build/azure-pipelines/common/retry.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
export async function retry<T>(fn: () => Promise<T>): Promise<T> {
|
||||
for (let run = 1; run <= 10; run++) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (err) {
|
||||
if (!/ECONNRESET/.test(err.message)) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
const millis = (Math.random() * 200) + (50 * Math.pow(1.5, run));
|
||||
console.log(`Failed with ECONNRESET, retrying in ${millis}ms...`);
|
||||
|
||||
// maximum delay is 10th retry: ~3 seconds
|
||||
await new Promise(c => setTimeout(c, millis));
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Retried too many times');
|
||||
}
|
|
@ -9,6 +9,7 @@ import * as url from 'url';
|
|||
import * as azure from 'azure-storage';
|
||||
import * as mime from 'mime';
|
||||
import { CosmosClient } from '@azure/cosmos';
|
||||
import { retry } from './retry';
|
||||
|
||||
function log(...args: any[]) {
|
||||
console.log(...[`[${new Date().toISOString()}]`, ...args]);
|
||||
|
@ -99,8 +100,8 @@ async function sync(commit: string, quality: string): Promise<void> {
|
|||
|
||||
log(` Updating build in DB...`);
|
||||
const mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`;
|
||||
await container.scripts.storedProcedure('setAssetMooncakeUrl')
|
||||
.execute('', [commit, asset.platform, asset.type, mooncakeUrl]);
|
||||
await retry(() => container.scripts.storedProcedure('setAssetMooncakeUrl')
|
||||
.execute('', [commit, asset.platform, asset.type, mooncakeUrl]));
|
||||
|
||||
log(` Done ✔️`);
|
||||
} catch (err) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -22,7 +22,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:
|
||||
|
@ -78,10 +78,9 @@ steps:
|
|||
|
||||
- script: |
|
||||
set -e
|
||||
npm install -g node-gyp@7.1.0
|
||||
npm install -g node-gyp@latest
|
||||
node-gyp --version
|
||||
displayName: Update node-gyp
|
||||
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
|
|
@ -8,7 +8,7 @@ pr:
|
|||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "12.14.1"
|
||||
versionSpec: "12.18.3"
|
||||
|
||||
- task: AzureKeyVault@1
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
pool:
|
||||
vmImage: "Ubuntu-16.04"
|
||||
|
||||
trigger:
|
||||
branches:
|
||||
include: ["master"]
|
||||
pr:
|
||||
branches:
|
||||
include: ["master"]
|
||||
trigger: none
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "12.14.1"
|
||||
versionSpec: "12.18.3"
|
||||
|
||||
- task: AzureKeyVault@1
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
|
|
|
@ -10,7 +10,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:
|
||||
|
|
|
@ -22,7 +22,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:
|
||||
|
|
|
@ -22,7 +22,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:
|
||||
|
@ -71,6 +71,18 @@ steps:
|
|||
|
||||
- script: |
|
||||
set -e
|
||||
npm install -g node-gyp@latest
|
||||
node-gyp --version
|
||||
displayName: Update node-gyp
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
if [ -z "$CC" || -z "$CXX" ]
|
||||
then
|
||||
export CC=$(which gcc-5)
|
||||
export CXX=$(which g++-5)
|
||||
fi
|
||||
export npm_config_arch=$(NPM_ARCH)
|
||||
export CHILD_CONCURRENCY="1"
|
||||
for i in {1..3}; do # try 3 times, for Terrapin
|
||||
|
@ -97,6 +109,16 @@ steps:
|
|||
displayName: Run postinstall scripts
|
||||
condition: and(succeeded(), eq(variables['CacheRestored'], 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
export CC=$(which gcc-4.8)
|
||||
export CXX=$(which g++-4.8)
|
||||
export npm_config_node_gyp=$(which node-gyp)
|
||||
cd remote && rm -rf node_modules/
|
||||
yarn
|
||||
displayName: Rebuild remote modules with gcc-4.8
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
node build/azure-pipelines/mixin
|
||||
|
@ -112,12 +134,6 @@ steps:
|
|||
yarn gulp vscode-reh-web-linux-$(VSCODE_ARCH)-min-ci
|
||||
displayName: Build
|
||||
|
||||
- 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
|
||||
DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests"
|
||||
|
@ -137,6 +153,7 @@ steps:
|
|||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)
|
||||
APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName")
|
||||
INTEGRATION_TEST_APP_NAME="$APP_NAME" \
|
||||
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \
|
||||
DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests"
|
||||
|
@ -154,6 +171,7 @@ steps:
|
|||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)
|
||||
APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName")
|
||||
INTEGRATION_TEST_APP_NAME="$APP_NAME" \
|
||||
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \
|
||||
DISPLAY=:10 ./resources/server/test/test-remote-integration.sh
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -11,8 +11,9 @@ schedules:
|
|||
resources:
|
||||
containers:
|
||||
- container: vscode-x64
|
||||
image: vscodehub.azurecr.io/vscode-linux-build-agent:x64
|
||||
image: vscodehub.azurecr.io/vscode-linux-build-agent:bionic-x64
|
||||
endpoint: VSCodeHub
|
||||
options: --user 0:0
|
||||
- container: vscode-arm64
|
||||
image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-arm64
|
||||
endpoint: VSCodeHub
|
||||
|
@ -27,7 +28,7 @@ stages:
|
|||
jobs:
|
||||
- job: Compile
|
||||
pool:
|
||||
vmImage: "Ubuntu-16.04"
|
||||
vmImage: "Ubuntu-18.04"
|
||||
container: vscode-x64
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
|
@ -70,7 +71,7 @@ stages:
|
|||
- Compile
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'))
|
||||
pool:
|
||||
vmImage: "Ubuntu-16.04"
|
||||
vmImage: "Ubuntu-18.04"
|
||||
jobs:
|
||||
- job: Linux
|
||||
condition: and(succeeded(), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
|
||||
|
@ -179,7 +180,7 @@ stages:
|
|||
- macOSARM64
|
||||
condition: and(succeededOrFailed(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'))
|
||||
pool:
|
||||
vmImage: "Ubuntu-16.04"
|
||||
vmImage: "Ubuntu-18.04"
|
||||
jobs:
|
||||
- job: SyncMooncake
|
||||
displayName: Sync Mooncake
|
||||
|
@ -194,7 +195,7 @@ stages:
|
|||
- 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-16.04"
|
||||
vmImage: "Ubuntu-18.04"
|
||||
jobs:
|
||||
- job: BuildService
|
||||
displayName: Build Service
|
||||
|
|
|
@ -17,7 +17,7 @@ steps:
|
|||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "12.14.1"
|
||||
versionSpec: "12.18.3"
|
||||
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
|
|
|
@ -9,7 +9,7 @@ pr: none
|
|||
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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -22,7 +22,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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -22,7 +22,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:
|
||||
|
|
|
@ -29,7 +29,6 @@ async function main(): Promise<void> {
|
|||
const appFrameworkPath = path.join(appRoot, appName, 'Contents', 'Frameworks');
|
||||
const helperAppBaseName = product.nameShort;
|
||||
const gpuHelperAppName = helperAppBaseName + ' Helper (GPU).app';
|
||||
const pluginHelperAppName = helperAppBaseName + ' Helper (Plugin).app';
|
||||
const rendererHelperAppName = helperAppBaseName + ' Helper (Renderer).app';
|
||||
|
||||
const defaultOpts: codesign.SignOptions = {
|
||||
|
@ -51,7 +50,6 @@ async function main(): Promise<void> {
|
|||
// TODO(deepak1556): Incorrectly declared type in electron-osx-sign
|
||||
ignore: (filePath: string) => {
|
||||
return filePath.includes(gpuHelperAppName) ||
|
||||
filePath.includes(pluginHelperAppName) ||
|
||||
filePath.includes(rendererHelperAppName);
|
||||
}
|
||||
};
|
||||
|
@ -63,13 +61,6 @@ async function main(): Promise<void> {
|
|||
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist'),
|
||||
};
|
||||
|
||||
const pluginHelperOpts: codesign.SignOptions = {
|
||||
...defaultOpts,
|
||||
app: path.join(appFrameworkPath, pluginHelperAppName),
|
||||
entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'),
|
||||
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'),
|
||||
};
|
||||
|
||||
const rendererHelperOpts: codesign.SignOptions = {
|
||||
...defaultOpts,
|
||||
app: path.join(appFrameworkPath, rendererHelperAppName),
|
||||
|
@ -78,7 +69,6 @@ async function main(): Promise<void> {
|
|||
};
|
||||
|
||||
await codesign.signAsync(gpuHelperOpts);
|
||||
await codesign.signAsync(pluginHelperOpts);
|
||||
await codesign.signAsync(rendererHelperOpts);
|
||||
await codesign.signAsync(appOpts as any);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ const vscodeResources = [
|
|||
'out-build/bootstrap-node.js',
|
||||
'out-build/bootstrap-window.js',
|
||||
'out-build/paths.js',
|
||||
'out-build/vs/**/*.{svg,png,html}',
|
||||
'out-build/vs/**/*.{svg,png,html,jpg}',
|
||||
'!out-build/vs/code/browser/**/*.html',
|
||||
'!out-build/vs/editor/standalone/**/*.svg',
|
||||
'out-build/vs/base/common/performance.js',
|
||||
|
@ -80,7 +80,6 @@ const vscodeResources = [
|
|||
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
|
||||
'out-build/vs/code/electron-sandbox/issue/issueReporter.js',
|
||||
'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.js',
|
||||
'out-build/vs/code/electron-sandbox/proxy/auth.js',
|
||||
'!**/test/**'
|
||||
];
|
||||
|
||||
|
@ -201,7 +200,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
|||
|
||||
const telemetry = gulp.src('.build/telemetry/**', { base: '.build/telemetry', dot: true });
|
||||
|
||||
const jsFilter = util.filter(data => !data.isDirectory() &&/\.js$/.test(data.path));
|
||||
const jsFilter = util.filter(data => !data.isDirectory() && /\.js$/.test(data.path));
|
||||
const root = path.resolve(path.join(__dirname, '..'));
|
||||
const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`]));
|
||||
|
||||
|
@ -338,7 +337,7 @@ BUILD_TARGETS.forEach(buildTarget => {
|
|||
const arch = buildTarget.arch;
|
||||
const opts = buildTarget.opts;
|
||||
|
||||
['', 'min'].forEach(minified => {
|
||||
const [vscode, vscodeMin] = ['', 'min'].map(minified => {
|
||||
const sourceFolderName = `out-vscode${dashed(minified)}`;
|
||||
const destinationFolderName = `VSCode${dashed(platform)}${dashed(arch)}`;
|
||||
|
||||
|
@ -355,7 +354,14 @@ BUILD_TARGETS.forEach(buildTarget => {
|
|||
vscodeTaskCI
|
||||
));
|
||||
gulp.task(vscodeTask);
|
||||
|
||||
return vscodeTask;
|
||||
});
|
||||
|
||||
if (process.platform === platform && process.arch === arch) {
|
||||
gulp.task(task.define('vscode', task.series(vscode)));
|
||||
gulp.task(task.define('vscode-min', task.series(vscodeMin)));
|
||||
}
|
||||
});
|
||||
|
||||
// Transifex Localizations
|
||||
|
|
|
@ -98,6 +98,7 @@ function prepareDebPackage(arch) {
|
|||
.pipe(replace('@@ARCHITECTURE@@', debArch))
|
||||
.pipe(replace('@@QUALITY@@', product.quality || '@@QUALITY@@'))
|
||||
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
|
||||
.pipe(replace('@@REPOSITORY_NAME@@', arch === 'x64' ? 'vscode' : 'code'))
|
||||
.pipe(rename('DEBIAN/postinst'));
|
||||
|
||||
const all = es.merge(control, postinst, postrm, prerm, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, code);
|
||||
|
|
|
@ -25,8 +25,6 @@ import { match } from 'minimatch';
|
|||
// Feel free to add more core types as you see needed if present in node.js and browsers
|
||||
const CORE_TYPES = [
|
||||
'require', // from our AMD loader
|
||||
// 'atob',
|
||||
// 'btoa',
|
||||
'setTimeout',
|
||||
'clearTimeout',
|
||||
'setInterval',
|
||||
|
|
|
@ -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": "415c1f9e9b35d9599b1a8ad1200476afa47a3323"
|
||||
"commitHash": "b0862a6e63173c4c919bd5ed27d257235bbfe7d2"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"license": "MIT",
|
||||
"version": "9.3.5"
|
||||
"version": "11.0.3"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
|
|
@ -81,7 +81,7 @@ function registerExtensionsCompletionsInExtensionsDocument(): vscode.Disposable
|
|||
const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
|
||||
if (location.path[0] === 'recommendations') {
|
||||
const extensionsContent = <IExtensionsContent>parse(document.getText());
|
||||
return provideInstalledExtensionProposals(extensionsContent && extensionsContent.recommendations || [], range, false);
|
||||
return provideInstalledExtensionProposals(extensionsContent && extensionsContent.recommendations || [], '', range, false);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ function registerExtensionsCompletionsInWorkspaceConfigurationDocument(): vscode
|
|||
const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
|
||||
if (location.path[0] === 'extensions' && location.path[1] === 'recommendations') {
|
||||
const extensionsContent = <IExtensionsContent>parse(document.getText())['extensions'];
|
||||
return provideInstalledExtensionProposals(extensionsContent && extensionsContent.recommendations || [], range, false);
|
||||
return provideInstalledExtensionProposals(extensionsContent && extensionsContent.recommendations || [], '', range, false);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@ import * as nls from 'vscode-nls';
|
|||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
||||
export function provideInstalledExtensionProposals(existing: string[], range: vscode.Range, includeBuiltinExtensions: boolean): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
|
||||
export function provideInstalledExtensionProposals(existing: string[], additionalText: string, range: vscode.Range, includeBuiltinExtensions: boolean): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
|
||||
if (Array.isArray(existing)) {
|
||||
const extensions = includeBuiltinExtensions ? vscode.extensions.all : vscode.extensions.all.filter(e => !(e.id.startsWith('vscode.') || e.id === 'Microsoft.vscode-markdown'));
|
||||
const knownExtensionProposals = extensions.filter(e => existing.indexOf(e.id) === -1);
|
||||
if (knownExtensionProposals.length) {
|
||||
return knownExtensionProposals.map(e => {
|
||||
const item = new vscode.CompletionItem(e.id);
|
||||
const insertText = `"${e.id}"`;
|
||||
const insertText = `"${e.id}"${additionalText}`;
|
||||
item.kind = vscode.CompletionItemKind.Value;
|
||||
item.insertText = insertText;
|
||||
item.range = range;
|
||||
|
|
|
@ -48,7 +48,16 @@ export class SettingsDocument {
|
|||
try {
|
||||
ignoredExtensions = parse(this.document.getText())['settingsSync.ignoredExtensions'];
|
||||
} catch (e) {/* ignore error */ }
|
||||
return provideInstalledExtensionProposals(ignoredExtensions, range, true);
|
||||
return provideInstalledExtensionProposals(ignoredExtensions, '', range, true);
|
||||
}
|
||||
|
||||
// remote.extensionKind
|
||||
if (location.path[0] === 'remote.extensionKind' && location.path.length === 2 && location.isAtPropertyKey) {
|
||||
let alreadyConfigured: string[] = [];
|
||||
try {
|
||||
alreadyConfigured = Object.keys(parse(this.document.getText())['remote.extensionKind']);
|
||||
} catch (e) {/* ignore error */ }
|
||||
return provideInstalledExtensionProposals(alreadyConfigured, `: [\n\t"ui"\n]`, range, true);
|
||||
}
|
||||
|
||||
return this.provideLanguageOverridesCompletionItems(location, position);
|
||||
|
|
|
@ -156,7 +156,7 @@ async function toggleAutoAttachSetting(context: vscode.ExtensionContext, scope?:
|
|||
|
||||
quickPick.show();
|
||||
|
||||
const result = await new Promise<PickResult>(resolve => {
|
||||
let result = await new Promise<PickResult>(resolve => {
|
||||
quickPick.onDidAccept(() => resolve(quickPick.selectedItems[0]));
|
||||
quickPick.onDidHide(() => resolve(undefined));
|
||||
quickPick.onDidTriggerButton(() => {
|
||||
|
@ -179,7 +179,11 @@ async function toggleAutoAttachSetting(context: vscode.ExtensionContext, scope?:
|
|||
}
|
||||
|
||||
if ('state' in result) {
|
||||
section.update(SETTING_STATE, result.state, scope);
|
||||
if (result.state !== current) {
|
||||
section.update(SETTING_STATE, result.state, scope);
|
||||
} else if (isTemporarilyDisabled) {
|
||||
result = { setTempDisabled: false };
|
||||
}
|
||||
}
|
||||
|
||||
if ('setTempDisabled' in result) {
|
||||
|
|
|
@ -54,7 +54,7 @@ class CheckoutRemoteHeadItem extends CheckoutItem {
|
|||
return localize('remote branch at', "Remote branch at {0}", this.shortCommit);
|
||||
}
|
||||
|
||||
async run(repository: Repository): Promise<void> {
|
||||
async run(repository: Repository, opts?: { detached?: boolean }): Promise<void> {
|
||||
if (!this.ref.name) {
|
||||
return;
|
||||
}
|
||||
|
@ -62,9 +62,9 @@ class CheckoutRemoteHeadItem extends CheckoutItem {
|
|||
const branches = await repository.findTrackingBranches(this.ref.name);
|
||||
|
||||
if (branches.length > 0) {
|
||||
await repository.checkout(branches[0].name!);
|
||||
await repository.checkout(branches[0].name!, opts);
|
||||
} else {
|
||||
await repository.checkoutTracking(this.ref.name);
|
||||
await repository.checkoutTracking(this.ref.name, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1264,8 +1264,8 @@ export class Repository implements Disposable {
|
|||
await this.run(Operation.Checkout, () => this.repository.checkout(treeish, [], opts));
|
||||
}
|
||||
|
||||
async checkoutTracking(treeish: string): Promise<void> {
|
||||
await this.run(Operation.CheckoutTracking, () => this.repository.checkout(treeish, [], { track: true }));
|
||||
async checkoutTracking(treeish: string, opts: { detached?: boolean } = {}): Promise<void> {
|
||||
await this.run(Operation.CheckoutTracking, () => this.repository.checkout(treeish, [], { ...opts, track: true }));
|
||||
}
|
||||
|
||||
async findTrackingBranches(upstreamRef: string): Promise<Branch[]> {
|
||||
|
|
|
@ -144,7 +144,7 @@
|
|||
"null"
|
||||
],
|
||||
"scope": "resource",
|
||||
"default": "null",
|
||||
"default": null,
|
||||
"description": "%html.format.wrapAttributesIndentSize.desc%"
|
||||
},
|
||||
"html.format.templating": {
|
||||
|
|
|
@ -17,6 +17,18 @@
|
|||
]
|
||||
],
|
||||
"autoClosingPairs": [
|
||||
[
|
||||
"{",
|
||||
"}"
|
||||
],
|
||||
[
|
||||
"[",
|
||||
"]"
|
||||
],
|
||||
[
|
||||
"(",
|
||||
")"
|
||||
],
|
||||
{
|
||||
"open": "'",
|
||||
"close": "'",
|
||||
|
|
|
@ -34,7 +34,7 @@ export default class MarkdownSmartSelect implements vscode.SelectionRangeProvide
|
|||
|
||||
const tokens = await this.engine.parse(document);
|
||||
|
||||
const blockTokens = getBlockTokensForPosition(tokens, position);
|
||||
const blockTokens = getBlockTokensForPosition(tokens, position, headerRange);
|
||||
|
||||
if (blockTokens.length === 0) {
|
||||
return undefined;
|
||||
|
@ -91,13 +91,13 @@ function createHeaderRange(header: TocEntry, isClosestHeaderToPosition: boolean,
|
|||
// of this header then all content then header
|
||||
return new vscode.SelectionRange(contentRange.with(undefined, startOfChildRange), new vscode.SelectionRange(contentRange, (new vscode.SelectionRange(range, parent))));
|
||||
} else {
|
||||
// no children and not on this header line so select content then header
|
||||
// not on this header line so select content then header
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent));
|
||||
}
|
||||
}
|
||||
|
||||
function getBlockTokensForPosition(tokens: Token[], position: vscode.Position): Token[] {
|
||||
const enclosingTokens = tokens.filter(token => token.map && (token.map[0] <= position.line && token.map[1] > position.line) && isBlockElement(token));
|
||||
function getBlockTokensForPosition(tokens: Token[], position: vscode.Position, parent?: vscode.SelectionRange): Token[] {
|
||||
const enclosingTokens = tokens.filter(token => token.map && (token.map[0] <= position.line && token.map[1] > position.line) && (!parent || (token.map[0] >= parent.range.start.line && token.map[1] <= parent.range.end.line + 1)) && isBlockElement(token));
|
||||
if (enclosingTokens.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
@ -131,9 +131,17 @@ function createInlineRange(document: vscode.TextDocument, cursorPosition: vscode
|
|||
const lineText = document.lineAt(cursorPosition.line).text;
|
||||
const boldSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, parent);
|
||||
const italicSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, parent);
|
||||
const linkSelection = createLinkRange(lineText, cursorPosition.character, cursorPosition.line, boldSelection ? boldSelection : italicSelection || parent);
|
||||
let comboSelection: vscode.SelectionRange | undefined;
|
||||
if (boldSelection && italicSelection && !boldSelection.range.isEqual(italicSelection.range)) {
|
||||
if (boldSelection.range.contains(italicSelection.range)) {
|
||||
comboSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, boldSelection);
|
||||
} else if (italicSelection.range.contains(boldSelection.range)) {
|
||||
comboSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, italicSelection);
|
||||
}
|
||||
}
|
||||
const linkSelection = createLinkRange(lineText, cursorPosition.character, cursorPosition.line, comboSelection || boldSelection || italicSelection || parent);
|
||||
const inlineCodeBlockSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, false, linkSelection || parent);
|
||||
return inlineCodeBlockSelection || linkSelection || boldSelection || italicSelection;
|
||||
return inlineCodeBlockSelection || linkSelection || comboSelection || boldSelection || italicSelection;
|
||||
}
|
||||
|
||||
function createFencedRange(token: Token, cursorLine: number, document: vscode.TextDocument, parent?: vscode.SelectionRange): vscode.SelectionRange {
|
||||
|
@ -154,61 +162,31 @@ function createFencedRange(token: Token, cursorLine: number, document: vscode.Te
|
|||
}
|
||||
|
||||
function createBoldRange(lineText: string, cursorChar: number, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
// find closest ** that occurs before cursor position
|
||||
let startBold = lineText.substring(0, cursorChar).lastIndexOf('**');
|
||||
|
||||
// find closest ** that occurs after the start **
|
||||
const endBoldIndex = lineText.substring(startBold + 2).indexOf('**');
|
||||
let endBold = startBold + 2 + lineText.substring(startBold + 2).indexOf('**');
|
||||
|
||||
if (startBold >= 0 && endBoldIndex >= 0 && startBold + 1 < endBold && startBold <= cursorChar && endBold >= cursorChar) {
|
||||
const range = new vscode.Range(cursorLine, startBold, cursorLine, endBold + 2);
|
||||
// **content cursor content** so select content then ** on both sides
|
||||
const contentRange = new vscode.Range(cursorLine, startBold + 2, cursorLine, endBold);
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent));
|
||||
} else if (startBold >= 0) {
|
||||
// **content**cursor or **content*cursor*
|
||||
// find end ** from end of start ** to end of line (since the cursor is within the end stars)
|
||||
let adjustedEnd = startBold + 2 + lineText.substring(startBold + 2).indexOf('**');
|
||||
startBold = lineText.substring(0, adjustedEnd - 2).lastIndexOf('**');
|
||||
if (adjustedEnd >= 0 && cursorChar === adjustedEnd || cursorChar === adjustedEnd + 1) {
|
||||
if (lineText.charAt(adjustedEnd + 1) === '*') {
|
||||
// *cursor* so need to extend end to include the second *
|
||||
adjustedEnd += 1;
|
||||
}
|
||||
return new vscode.SelectionRange(new vscode.Range(cursorLine, startBold, cursorLine, adjustedEnd + 1), parent);
|
||||
}
|
||||
} else if (endBold > 0) {
|
||||
// cursor**content** or *cursor*content**
|
||||
// find start ** from start of string to cursor + 2 (since the cursor is within the start stars)
|
||||
const adjustedStart = lineText.substring(0, cursorChar + 2).lastIndexOf('**');
|
||||
endBold = adjustedStart + 2 + lineText.substring(adjustedStart + 2).indexOf('**');
|
||||
if (adjustedStart >= 0 && adjustedStart === cursorChar || adjustedStart === cursorChar - 1) {
|
||||
return new vscode.SelectionRange(new vscode.Range(cursorLine, adjustedStart, cursorLine, endBold + 2), parent);
|
||||
}
|
||||
const regex = /(?:^|(?<=\s))(?:\*\*\s*([^*]+)(?:\*\s*([^*]+)\s*?\*)*([^*]+)\s*?\*\*)/g;
|
||||
const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar);
|
||||
if (matches.length > 0) {
|
||||
// should only be one match, so select first and index 0 contains the entire match
|
||||
const bold = matches[0][0];
|
||||
const startIndex = lineText.indexOf(bold);
|
||||
const cursorOnStars = cursorChar === startIndex || cursorChar === startIndex + 1 || cursorChar === startIndex + bold.length || cursorChar === startIndex + bold.length - 1;
|
||||
const contentAndStars = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + bold.length), parent);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 2, cursorLine, startIndex + bold.length - 2), contentAndStars);
|
||||
return cursorOnStars ? contentAndStars : content;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function createOtherInlineRange(lineText: string, cursorChar: number, cursorLine: number, isItalic: boolean, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
const type = isItalic ? '*' : '`';
|
||||
const start = lineText.substring(0, cursorChar + 1).lastIndexOf(type);
|
||||
let end = lineText.substring(cursorChar).indexOf(type);
|
||||
|
||||
if (start >= 0 && end >= 0) {
|
||||
end += cursorChar;
|
||||
// ensure there's no * or ` before end
|
||||
const intermediate = lineText.substring(start + 1, end - 1).indexOf(type);
|
||||
if (intermediate < 0) {
|
||||
const range = new vscode.Range(cursorLine, start, cursorLine, end + 1);
|
||||
if (cursorChar > start && cursorChar <= end) {
|
||||
// within the content so select content then include the stars or backticks
|
||||
const contentRange = new vscode.Range(cursorLine, start + 1, cursorLine, end);
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent));
|
||||
} else if (cursorChar === start) {
|
||||
return new vscode.SelectionRange(range, parent);
|
||||
}
|
||||
}
|
||||
const regex = isItalic ? /(?:^|(?<=\s))(?:\*\s*([^*]+)(?:\*\*\s*([^*]+)\s*?\*\*)*([^*]+)\s*?\*)/g : /\`[^\`]*\`/g;
|
||||
const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar);
|
||||
if (matches.length > 0) {
|
||||
// should only be one match, so select first and index 0 contains the entire match
|
||||
const match = matches[0][0];
|
||||
const startIndex = lineText.indexOf(match);
|
||||
const cursorOnType = cursorChar === startIndex || cursorChar === startIndex + match.length;
|
||||
const contentAndType = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + match.length), parent);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 1, cursorLine, startIndex + match.length - 1), contentAndType);
|
||||
return cursorOnType ? contentAndType : content;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
@ -228,11 +206,12 @@ function createLinkRange(lineText: string, cursorChar: number, cursorLine: numbe
|
|||
// determine if cursor is within [text] or (url) in order to know which should be selected
|
||||
const nearestType = cursorChar >= lineText.indexOf(linkText) && cursorChar < lineText.indexOf(linkText) + linkText.length ? linkText : url;
|
||||
|
||||
const indexOfType = lineText.indexOf(nearestType);
|
||||
// determine if cursor is on a bracket or paren and if so, return the [content] or (content), skipping over the content range
|
||||
const cursorOnType = cursorChar === lineText.indexOf(nearestType) || cursorChar === lineText.indexOf(nearestType) + nearestType.length;
|
||||
const cursorOnType = cursorChar === indexOfType || cursorChar === indexOfType + nearestType.length;
|
||||
|
||||
const contentAndNearestType = new vscode.SelectionRange(new vscode.Range(cursorLine, lineText.indexOf(nearestType), cursorLine, lineText.indexOf(nearestType) + nearestType.length), linkRange);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, lineText.indexOf(nearestType) + 1, cursorLine, lineText.indexOf(nearestType) + nearestType.length - 1), contentAndNearestType);
|
||||
const contentAndNearestType = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType, cursorLine, indexOfType + nearestType.length), linkRange);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType + 1, cursorLine, indexOfType + nearestType.length - 1), contentAndNearestType);
|
||||
return cursorOnType ? contentAndNearestType : content;
|
||||
}
|
||||
return undefined;
|
||||
|
|
|
@ -520,10 +520,10 @@ suite('markdown.SmartSelect', () => {
|
|||
`paragraph`,
|
||||
`## sub header`,
|
||||
`- list`,
|
||||
`- stuff here [text]**${CURSOR}items in here** and **here**`,
|
||||
`- stuff here [text] **${CURSOR}items in here** and **here**`,
|
||||
`- list`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [6, 21, 6, 44], [6, 19, 6, 46], [6, 0, 6, 59], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]);
|
||||
assertNestedRangesEqual(ranges![0], [6, 22, 6, 45], [6, 20, 6, 47], [6, 0, 6, 60], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]);
|
||||
});
|
||||
test('Smart select link in paragraph with multiple links', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
|
@ -567,11 +567,69 @@ suite('markdown.SmartSelect', () => {
|
|||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 2, 0, 21], [0, 1, 0, 22], [0, 1, 0, 42], [0, 1, 0, 42], [0, 0, 0, 43], [0, 0, 0, 43]);
|
||||
});
|
||||
test('Smart select italic on end', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`*word1 word2 word3${CURSOR}*`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 1, 0, 28], [0, 0, 0, 29], [0, 0, 0, 29]);
|
||||
});
|
||||
test('Smart select italic then bold', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`outer text **bold words *italic ${CURSOR} words* bold words** outer text`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 25, 0, 48], [0, 24, 0, 49], [0, 13, 0, 60], [0, 11, 0, 62], [0, 0, 0, 73]);
|
||||
});
|
||||
test('Smart select bold then italic', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`outer text *italic words **bold ${CURSOR} words** italic words* outer text`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 27, 0, 48], [0, 25, 0, 50], [0, 12, 0, 63], [0, 11, 0, 64], [0, 0, 0, 75]);
|
||||
});
|
||||
test('Third level header from release notes', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`---`,
|
||||
`Order: 60`,
|
||||
`TOCTitle: October 2020`,
|
||||
`PageTitle: Visual Studio Code October 2020`,
|
||||
`MetaDescription: Learn what is new in the Visual Studio Code October 2020 Release (1.51)`,
|
||||
`MetaSocialImage: 1_51/release-highlights.png`,
|
||||
`Date: 2020-11-6`,
|
||||
`DownloadVersion: 1.51.1`,
|
||||
`---`,
|
||||
`# October 2020 (version 1.51)`,
|
||||
``,
|
||||
`**Update 1.51.1**: The update addresses these [issues](https://github.com/microsoft/vscode/issues?q=is%3Aissue+milestone%3A%22October+2020+Recovery%22+is%3Aclosed+).`,
|
||||
``,
|
||||
`<!-- DOWNLOAD_LINKS_PLACEHOLDER -->`,
|
||||
``,
|
||||
`---`,
|
||||
``,
|
||||
`Welcome to the October 2020 release of Visual Studio Code. As announced in the [October iteration plan](https://github.com/microsoft/vscode/issues/108473), we focused on housekeeping GitHub issues and pull requests as documented in our issue grooming guide.`,
|
||||
``,
|
||||
`We also worked with our partners at GitHub on GitHub Codespaces, which ended up being more involved than originally anticipated. To that end, we'll continue working on housekeeping for part of the November iteration.`,
|
||||
``,
|
||||
`During this housekeeping milestone, we also addressed several feature requests and community [pull requests](#thank-you). Read on to learn about new features and settings.`,
|
||||
``,
|
||||
`## Workbench`,
|
||||
``,
|
||||
`### More prominent pinned tabs`,
|
||||
``,
|
||||
`${CURSOR}Pinned tabs will now always show their pin icon, even while inactive, to make them easier to identify. If an editor is both pinned and contains unsaved changes, the icon reflects both states.`,
|
||||
``,
|
||||
`![Inactive pinned tabs showing pin icons](images/1_51/pinned-tabs.png)`
|
||||
)
|
||||
);
|
||||
assertNestedRangesEqual(ranges![0], [27, 0, 27, 201], [26, 0, 29, 70], [25, 0, 29, 70], [24, 0, 29, 70], [23, 0, 29, 70], [10, 0, 29, 70], [9, 0, 29, 70]);
|
||||
});
|
||||
});
|
||||
|
||||
function assertNestedLineNumbersEqual(range: vscode.SelectionRange, ...expectedRanges: [number, number][]) {
|
||||
const lineage = getLineage(range);
|
||||
assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length}`);
|
||||
assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length} ${getValues(lineage)}`);
|
||||
for (let i = 0; i < lineage.length; i++) {
|
||||
assertLineNumbersEqual(lineage[i], expectedRanges[i][0], expectedRanges[i][1], `parent at a depth of ${i}`);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export function runSelectedScript() {
|
||||
export function runSelectedScript(context: vscode.ExtensionContext) {
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
|
@ -27,15 +27,15 @@ export function runSelectedScript() {
|
|||
|
||||
let script = findScriptAtPosition(contents, offset);
|
||||
if (script) {
|
||||
runScript(script, document);
|
||||
runScript(context, script, document);
|
||||
} else {
|
||||
let message = localize('noScriptFound', 'Could not find a valid npm script at the selection.');
|
||||
vscode.window.showErrorMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
export async function selectAndRunScriptFromFolder(selectedFolder: vscode.Uri) {
|
||||
let taskList: FolderTaskItem[] = await detectNpmScriptsForFolder(selectedFolder);
|
||||
export async function selectAndRunScriptFromFolder(context: vscode.ExtensionContext, selectedFolder: vscode.Uri) {
|
||||
let taskList: FolderTaskItem[] = await detectNpmScriptsForFolder(context, selectedFolder);
|
||||
|
||||
if (taskList && taskList.length > 0) {
|
||||
const quickPick = vscode.window.createQuickPick<FolderTaskItem>();
|
||||
|
|
|
@ -58,7 +58,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
|||
}));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('npm.packageManager', (args) => {
|
||||
if (args instanceof vscode.Uri) {
|
||||
return getPackageManager(args);
|
||||
return getPackageManager(context, args);
|
||||
}
|
||||
return '';
|
||||
}));
|
||||
|
@ -83,7 +83,7 @@ function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposab
|
|||
let workspaceWatcher = vscode.workspace.onDidChangeWorkspaceFolders((_e) => invalidateScriptCaches());
|
||||
context.subscriptions.push(workspaceWatcher);
|
||||
|
||||
taskProvider = new NpmTaskProvider();
|
||||
taskProvider = new NpmTaskProvider(context);
|
||||
let disposable = vscode.tasks.registerTaskProvider('npm', taskProvider);
|
||||
context.subscriptions.push(disposable);
|
||||
return disposable;
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
} from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import {
|
||||
createTask, getTaskName, isAutoDetectionEnabled, isWorkspaceFolder, NpmTaskDefinition,
|
||||
createTask, getPackageManager, getTaskName, isAutoDetectionEnabled, isWorkspaceFolder, NpmTaskDefinition,
|
||||
NpmTaskProvider,
|
||||
startDebugging,
|
||||
TaskLocation,
|
||||
|
@ -132,7 +132,7 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider<TreeItem> {
|
|||
private _onDidChangeTreeData: EventEmitter<TreeItem | null> = new EventEmitter<TreeItem | null>();
|
||||
readonly onDidChangeTreeData: Event<TreeItem | null> = this._onDidChangeTreeData.event;
|
||||
|
||||
constructor(context: ExtensionContext, public taskProvider: NpmTaskProvider) {
|
||||
constructor(private context: ExtensionContext, public taskProvider: NpmTaskProvider) {
|
||||
const subscriptions = context.subscriptions;
|
||||
this.extensionContext = context;
|
||||
subscriptions.push(commands.registerCommand('npm.runScript', this.runScript, this));
|
||||
|
@ -142,11 +142,13 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider<TreeItem> {
|
|||
}
|
||||
|
||||
private async runScript(script: NpmScript) {
|
||||
// Call getPackageManager to trigger the multiple lock files warning.
|
||||
await getPackageManager(this.context, script.getFolder().uri);
|
||||
tasks.executeTask(script.task);
|
||||
}
|
||||
|
||||
private async debugScript(script: NpmScript) {
|
||||
startDebugging(script.task.definition.script, path.dirname(script.package.resourceUri!.fsPath), script.getFolder());
|
||||
startDebugging(this.extensionContext, script.task.definition.script, path.dirname(script.package.resourceUri!.fsPath), script.getFolder());
|
||||
}
|
||||
|
||||
private findScript(document: TextDocument, script?: NpmScript): number {
|
||||
|
@ -190,7 +192,7 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider<TreeItem> {
|
|||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
let task = await createTask('install', 'install', selection.folder.workspaceFolder, uri, undefined, []);
|
||||
let task = await createTask(this.extensionContext, 'install', 'install', selection.folder.workspaceFolder, uri, true, undefined, []);
|
||||
tasks.executeTask(task);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ export function invalidateHoverScriptsCache(document?: TextDocument) {
|
|||
|
||||
export class NpmScriptHoverProvider implements HoverProvider {
|
||||
|
||||
constructor(context: ExtensionContext) {
|
||||
constructor(private context: ExtensionContext) {
|
||||
context.subscriptions.push(commands.registerCommand('npm.runScriptFromHover', this.runScriptFromHover, this));
|
||||
context.subscriptions.push(commands.registerCommand('npm.debugScriptFromHover', this.debugScriptFromHover, this));
|
||||
context.subscriptions.push(workspace.onDidChangeTextDocument((e) => {
|
||||
|
@ -103,7 +103,7 @@ export class NpmScriptHoverProvider implements HoverProvider {
|
|||
let documentUri = args.documentUri;
|
||||
let folder = workspace.getWorkspaceFolder(documentUri);
|
||||
if (folder) {
|
||||
let task = await createTask(script, `run ${script}`, folder, documentUri);
|
||||
let task = await createTask(this.context, script, `run ${script}`, folder, documentUri);
|
||||
await tasks.executeTask(task);
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ export class NpmScriptHoverProvider implements HoverProvider {
|
|||
let documentUri = args.documentUri;
|
||||
let folder = workspace.getWorkspaceFolder(documentUri);
|
||||
if (folder) {
|
||||
startDebugging(script, dirname(documentUri.fsPath), folder);
|
||||
startDebugging(this.context, script, dirname(documentUri.fsPath), folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import {
|
||||
TaskDefinition, Task, TaskGroup, WorkspaceFolder, RelativePattern, ShellExecution, Uri, workspace,
|
||||
DebugConfiguration, debug, TaskProvider, TextDocument, tasks, TaskScope, QuickPickItem, window, Position
|
||||
DebugConfiguration, debug, TaskProvider, TextDocument, tasks, TaskScope, QuickPickItem, window, Position, ExtensionContext, env
|
||||
} from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
|
@ -44,15 +44,15 @@ export interface TaskWithLocation {
|
|||
|
||||
export class NpmTaskProvider implements TaskProvider {
|
||||
|
||||
constructor() {
|
||||
constructor(private context: ExtensionContext) {
|
||||
}
|
||||
|
||||
get tasksWithLocation(): Promise<TaskWithLocation[]> {
|
||||
return provideNpmScripts();
|
||||
return provideNpmScripts(this.context, false);
|
||||
}
|
||||
|
||||
public async provideTasks() {
|
||||
const tasks = await provideNpmScripts();
|
||||
const tasks = await provideNpmScripts(this.context, true);
|
||||
return tasks.map(task => task.task);
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ export class NpmTaskProvider implements TaskProvider {
|
|||
} else {
|
||||
packageJsonUri = _task.scope.uri.with({ path: _task.scope.uri.path + '/package.json' });
|
||||
}
|
||||
return createTask(kind, `${kind.script === INSTALL_SCRIPT ? '' : 'run '}${kind.script}`, _task.scope, packageJsonUri);
|
||||
return createTask(this.context, kind, `${kind.script === INSTALL_SCRIPT ? '' : 'run '}${kind.script}`, _task.scope, packageJsonUri);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
@ -123,16 +123,23 @@ export function isWorkspaceFolder(value: any): value is WorkspaceFolder {
|
|||
return value && typeof value !== 'number';
|
||||
}
|
||||
|
||||
export async function getPackageManager(folder: Uri): Promise<string> {
|
||||
export async function getPackageManager(extensionContext: ExtensionContext, folder: Uri, showWarning: boolean = true): Promise<string> {
|
||||
let packageManagerName = workspace.getConfiguration('npm', folder).get<string>('packageManager', 'npm');
|
||||
|
||||
if (packageManagerName === 'auto') {
|
||||
const { name, multiplePMDetected } = await findPreferredPM(folder.fsPath);
|
||||
packageManagerName = name;
|
||||
|
||||
if (multiplePMDetected) {
|
||||
const multiplePMWarning = localize('npm.multiplePMWarning', 'Found multiple lockfiles for {0}. Using {1} as the preferred package manager.', folder.fsPath, packageManagerName);
|
||||
window.showWarningMessage(multiplePMWarning);
|
||||
const neverShowWarning = 'npm.multiplePMWarning.neverShow';
|
||||
if (showWarning && multiplePMDetected && !extensionContext.globalState.get<boolean>(neverShowWarning)) {
|
||||
const multiplePMWarning = localize('npm.multiplePMWarning', 'Using {0} as the preferred package manager. Found multiple lockfiles for {1}.', packageManagerName, folder.fsPath);
|
||||
const neverShowAgain = localize('npm.multiplePMWarning.doNotShow', "Do not show again");
|
||||
const learnMore = localize('npm.multiplePMWarning.learnMore', "Learn more");
|
||||
window.showInformationMessage(multiplePMWarning, learnMore, neverShowAgain).then(result => {
|
||||
switch (result) {
|
||||
case neverShowAgain: extensionContext.globalState.update(neverShowWarning, true); break;
|
||||
case learnMore: env.openExternal(Uri.parse('https://nodejs.dev/learn/the-package-lock-json-file'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +167,7 @@ export async function hasNpmScripts(): Promise<boolean> {
|
|||
}
|
||||
}
|
||||
|
||||
async function detectNpmScripts(): Promise<TaskWithLocation[]> {
|
||||
async function detectNpmScripts(context: ExtensionContext, showWarning: boolean): Promise<TaskWithLocation[]> {
|
||||
|
||||
let emptyTasks: TaskWithLocation[] = [];
|
||||
let allTasks: TaskWithLocation[] = [];
|
||||
|
@ -177,7 +184,7 @@ async function detectNpmScripts(): Promise<TaskWithLocation[]> {
|
|||
let paths = await workspace.findFiles(relativePattern, '**/{node_modules,.vscode-test}/**');
|
||||
for (const path of paths) {
|
||||
if (!isExcluded(folder, path) && !visitedPackageJsonFiles.has(path.fsPath)) {
|
||||
let tasks = await provideNpmScriptsForFolder(path);
|
||||
let tasks = await provideNpmScriptsForFolder(context, path, showWarning);
|
||||
visitedPackageJsonFiles.add(path.fsPath);
|
||||
allTasks.push(...tasks);
|
||||
}
|
||||
|
@ -191,7 +198,7 @@ async function detectNpmScripts(): Promise<TaskWithLocation[]> {
|
|||
}
|
||||
|
||||
|
||||
export async function detectNpmScriptsForFolder(folder: Uri): Promise<FolderTaskItem[]> {
|
||||
export async function detectNpmScriptsForFolder(context: ExtensionContext, folder: Uri): Promise<FolderTaskItem[]> {
|
||||
|
||||
let folderTasks: FolderTaskItem[] = [];
|
||||
|
||||
|
@ -202,7 +209,7 @@ export async function detectNpmScriptsForFolder(folder: Uri): Promise<FolderTask
|
|||
let visitedPackageJsonFiles: Set<string> = new Set();
|
||||
for (const path of paths) {
|
||||
if (!visitedPackageJsonFiles.has(path.fsPath)) {
|
||||
let tasks = await provideNpmScriptsForFolder(path);
|
||||
let tasks = await provideNpmScriptsForFolder(context, path, true);
|
||||
visitedPackageJsonFiles.add(path.fsPath);
|
||||
folderTasks.push(...tasks.map(t => ({ label: t.task.name, task: t.task })));
|
||||
}
|
||||
|
@ -213,9 +220,9 @@ export async function detectNpmScriptsForFolder(folder: Uri): Promise<FolderTask
|
|||
}
|
||||
}
|
||||
|
||||
export async function provideNpmScripts(): Promise<TaskWithLocation[]> {
|
||||
export async function provideNpmScripts(context: ExtensionContext, showWarning: boolean): Promise<TaskWithLocation[]> {
|
||||
if (!cachedTasks) {
|
||||
cachedTasks = await detectNpmScripts();
|
||||
cachedTasks = await detectNpmScripts(context, showWarning);
|
||||
}
|
||||
return cachedTasks;
|
||||
}
|
||||
|
@ -251,7 +258,7 @@ function isDebugScript(script: string): boolean {
|
|||
return match !== null;
|
||||
}
|
||||
|
||||
async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise<TaskWithLocation[]> {
|
||||
async function provideNpmScriptsForFolder(context: ExtensionContext, packageJsonUri: Uri, showWarning: boolean): Promise<TaskWithLocation[]> {
|
||||
let emptyTasks: TaskWithLocation[] = [];
|
||||
|
||||
let folder = workspace.getWorkspaceFolder(packageJsonUri);
|
||||
|
@ -269,7 +276,7 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise<TaskWith
|
|||
|
||||
for (const each of scripts.keys()) {
|
||||
const scriptValue = scripts.get(each)!;
|
||||
const task = await createTask(each, `run ${each}`, folder!, packageJsonUri, scriptValue.script);
|
||||
const task = await createTask(context, each, `run ${each}`, folder!, packageJsonUri, showWarning, scriptValue.script);
|
||||
const lowerCaseTaskName = each.toLowerCase();
|
||||
if (isBuildTask(lowerCaseTaskName)) {
|
||||
task.group = TaskGroup.Build;
|
||||
|
@ -288,7 +295,7 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise<TaskWith
|
|||
}
|
||||
|
||||
// always add npm install (without a problem matcher)
|
||||
result.push({ task: await createTask(INSTALL_SCRIPT, INSTALL_SCRIPT, folder, packageJsonUri, 'install dependencies from package', []) });
|
||||
result.push({ task: await createTask(context, INSTALL_SCRIPT, INSTALL_SCRIPT, folder, packageJsonUri, showWarning, 'install dependencies from package', []) });
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -299,7 +306,7 @@ export function getTaskName(script: string, relativePath: string | undefined) {
|
|||
return script;
|
||||
}
|
||||
|
||||
export async function createTask(script: NpmTaskDefinition | string, cmd: string, folder: WorkspaceFolder, packageJsonUri: Uri, detail?: string, matcher?: any): Promise<Task> {
|
||||
export async function createTask(context: ExtensionContext, script: NpmTaskDefinition | string, cmd: string, folder: WorkspaceFolder, packageJsonUri: Uri, showWarning: boolean = true, detail?: string, matcher?: any): Promise<Task> {
|
||||
let kind: NpmTaskDefinition;
|
||||
if (typeof script === 'string') {
|
||||
kind = { type: 'npm', script: script };
|
||||
|
@ -307,7 +314,7 @@ export async function createTask(script: NpmTaskDefinition | string, cmd: string
|
|||
kind = script;
|
||||
}
|
||||
|
||||
const packageManager = await getPackageManager(folder.uri);
|
||||
const packageManager = await getPackageManager(context, folder.uri, showWarning);
|
||||
async function getCommandLine(cmd: string): Promise<string> {
|
||||
if (workspace.getConfiguration('npm', folder.uri).get<boolean>('runSilent')) {
|
||||
return `${packageManager} --silent ${cmd}`;
|
||||
|
@ -368,22 +375,22 @@ async function exists(file: string): Promise<boolean> {
|
|||
});
|
||||
}
|
||||
|
||||
export async function runScript(script: string, document: TextDocument) {
|
||||
export async function runScript(context: ExtensionContext, script: string, document: TextDocument) {
|
||||
let uri = document.uri;
|
||||
let folder = workspace.getWorkspaceFolder(uri);
|
||||
if (folder) {
|
||||
let task = await createTask(script, `run ${script}`, folder, uri);
|
||||
let task = await createTask(context, script, `run ${script}`, folder, uri);
|
||||
tasks.executeTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
export async function startDebugging(scriptName: string, cwd: string, folder: WorkspaceFolder) {
|
||||
export async function startDebugging(context: ExtensionContext, scriptName: string, cwd: string, folder: WorkspaceFolder) {
|
||||
const config: DebugConfiguration = {
|
||||
type: 'pwa-node',
|
||||
request: 'launch',
|
||||
name: `Debug ${scriptName}`,
|
||||
cwd,
|
||||
runtimeExecutable: await getPackageManager(folder.uri),
|
||||
runtimeExecutable: await getPackageManager(context, folder.uri),
|
||||
runtimeArgs: [
|
||||
'run',
|
||||
scriptName,
|
||||
|
|
|
@ -9,21 +9,14 @@
|
|||
"statusBarItem.remoteBackground": "#00000000",
|
||||
"sideBarTitle.foreground": "#FFFFFF"
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
"settings": {
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#000000"
|
||||
}
|
||||
},
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": [
|
||||
"meta.embedded",
|
||||
"source.groovy.embedded"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#000000"
|
||||
"foreground": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
14
package.json
14
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.52.0",
|
||||
"distro": "7c9caf8254b4e707f8f7637661df05d1397f2181",
|
||||
"version": "1.53.0",
|
||||
"distro": "1aaf2adfd4fd7c35c133724c4d97e103f2fa331f",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
@ -45,7 +45,7 @@
|
|||
"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",
|
||||
"electron-rebuild": "electron-rebuild --arch=arm64 --force --version=11.0.2"
|
||||
"electron-rebuild": "electron-rebuild --arch=arm64 --force --version=11.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"applicationinsights": "1.0.8",
|
||||
|
@ -60,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",
|
||||
|
@ -112,7 +112,7 @@
|
|||
"css-loader": "^3.2.0",
|
||||
"debounce": "^1.0.0",
|
||||
"deemon": "^1.4.0",
|
||||
"electron": "9.3.5",
|
||||
"electron": "11.0.3",
|
||||
"electron-rebuild": "2.0.3",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-plugin-jsdoc": "^19.1.0",
|
||||
|
@ -176,7 +176,7 @@
|
|||
"vinyl": "^2.0.0",
|
||||
"vinyl-fs": "^3.0.0",
|
||||
"vsce": "1.48.0",
|
||||
"vscode-debugprotocol": "1.41.0",
|
||||
"vscode-debugprotocol": "1.43.0",
|
||||
"vscode-nls-dev": "^3.3.1",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.12",
|
||||
|
@ -191,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",
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
"builtInExtensions": [
|
||||
{
|
||||
"name": "ms-vscode.node-debug",
|
||||
"version": "1.44.14",
|
||||
"version": "1.44.15",
|
||||
"repo": "https://github.com/microsoft/vscode-node-debug",
|
||||
"metadata": {
|
||||
"id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6",
|
||||
|
@ -91,7 +91,7 @@
|
|||
},
|
||||
{
|
||||
"name": "ms-vscode.js-debug",
|
||||
"version": "1.51.0",
|
||||
"version": "1.52.2",
|
||||
"repo": "https://github.com/microsoft/vscode-js-debug",
|
||||
"metadata": {
|
||||
"id": "25629058-ddac-4e17-abba-74678e126c5d",
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
disturl "http://nodejs.org/dist"
|
||||
target "12.14.1"
|
||||
target "12.18.3"
|
||||
runtime "node"
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -299,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"
|
||||
|
||||
|
@ -438,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"
|
||||
|
|
|
@ -73,6 +73,6 @@ NdCFTW7wY0Fb1fWJ+/KTsC4=
|
|||
if [ "$WRITE_SOURCE" -eq "1" ]; then
|
||||
echo "### THIS FILE IS AUTOMATICALLY CONFIGURED ###
|
||||
# You may comment out this entry, but any other modifications may be lost.
|
||||
deb [arch=amd64] http://packages.microsoft.com/repos/vscode stable main" > $CODE_SOURCE_PART
|
||||
deb [arch=amd64] http://packages.microsoft.com/repos/@@REPOSITORY_NAME@@ stable main" > $CODE_SOURCE_PART
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -377,11 +377,18 @@ async function handleRoot(req, res) {
|
|||
fancyLog(`${ansiColors.magenta('Additional extensions')}: ${staticExtensions.map(e => path.basename(e.extensionLocation.path)).join(', ') || 'None'}`);
|
||||
}
|
||||
|
||||
const secondaryHost = (
|
||||
req.headers['host']
|
||||
? req.headers['host'].replace(':' + PORT, ':' + SECONDARY_PORT)
|
||||
: `${HOST}:${SECONDARY_PORT}`
|
||||
);
|
||||
const webConfigJSON = {
|
||||
folderUri: folderUri,
|
||||
staticExtensions,
|
||||
enableSyncByDefault: args['enable-sync'],
|
||||
webWorkerExtensionHostIframeSrc: `${SCHEME}://${HOST}:${SECONDARY_PORT}/static/out/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html`
|
||||
settingsSyncOptions: {
|
||||
enabled: args['enable-sync']
|
||||
},
|
||||
webWorkerExtensionHostIframeSrc: `${SCHEME}://${secondaryHost}/static/out/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html`
|
||||
};
|
||||
if (args['wrap-iframe']) {
|
||||
webConfigJSON._wrapWebWorkerExtHostInIframe = true;
|
||||
|
|
|
@ -46,21 +46,48 @@ else
|
|||
echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build."
|
||||
fi
|
||||
|
||||
if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then
|
||||
after_suite() { true; }
|
||||
else
|
||||
after_suite() { killall $INTEGRATION_TEST_APP_NAME || true; }
|
||||
fi
|
||||
|
||||
# Integration tests in AMD
|
||||
./scripts/test.sh --runGlob **/*.integrationTest.js "$@"
|
||||
after_suite
|
||||
|
||||
# Tests in the extension host
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
after_suite
|
||||
|
||||
# TODO(deepak1556): Disable workspace test temporarily
|
||||
# https://github.com/microsoft/vscode/issues/111288
|
||||
#"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
#after_suite
|
||||
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
after_suite
|
||||
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
after_suite
|
||||
|
||||
#"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
# after_suite
|
||||
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
after_suite
|
||||
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
after_suite
|
||||
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
after_suite
|
||||
|
||||
# Tests in commonJS (CSS, HTML)
|
||||
cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
||||
after_suite
|
||||
|
||||
cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
||||
after_suite
|
||||
|
||||
rm -rf $VSCODEUSERDATADIR
|
||||
|
|
41
src/bootstrap-fork.js
vendored
41
src/bootstrap-fork.js
vendored
|
@ -135,18 +135,47 @@ function pipeLoggingToParent() {
|
|||
&& !(obj instanceof Date);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {'log' | 'warn' | 'error'} severity
|
||||
* @param {string} args
|
||||
*/
|
||||
function safeSendConsoleMessage(severity, args) {
|
||||
safeSend({ type: '__$console', severity, arguments: args });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {'log' | 'info' | 'warn' | 'error'} method
|
||||
* @param {'log' | 'warn' | 'error'} severity
|
||||
*/
|
||||
function wrapConsoleMethod(method, severity) {
|
||||
if (process.env.VSCODE_LOG_NATIVE === 'true') {
|
||||
const original = console[method];
|
||||
console[method] = function () {
|
||||
safeSendConsoleMessage(severity, safeToArray(arguments));
|
||||
|
||||
const stream = method === 'error' || method === 'warn' ? process.stderr : process.stdout;
|
||||
stream.write('\nSTART_NATIVE_LOG\n');
|
||||
original.apply(console, arguments);
|
||||
stream.write('\nEND_NATIVE_LOG\n');
|
||||
};
|
||||
} else {
|
||||
console[method] = function () { safeSendConsoleMessage(severity, safeToArray(arguments)); };
|
||||
}
|
||||
}
|
||||
|
||||
// Pass console logging to the outside so that we have it in the main side if told so
|
||||
if (process.env.VERBOSE_LOGGING === 'true') {
|
||||
console.log = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeToArray(arguments) }); };
|
||||
console.info = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeToArray(arguments) }); };
|
||||
console.warn = function () { safeSend({ type: '__$console', severity: 'warn', arguments: safeToArray(arguments) }); };
|
||||
} else {
|
||||
wrapConsoleMethod('info', 'log');
|
||||
wrapConsoleMethod('log', 'log');
|
||||
wrapConsoleMethod('warn', 'warn');
|
||||
wrapConsoleMethod('error', 'error');
|
||||
} else if (process.env.VSCODE_LOG_NATIVE !== 'true') {
|
||||
console.log = function () { /* ignore */ };
|
||||
console.warn = function () { /* ignore */ };
|
||||
console.info = function () { /* ignore */ };
|
||||
wrapConsoleMethod('error', 'error');
|
||||
}
|
||||
|
||||
console.error = function () { safeSend({ type: '__$console', severity: 'error', arguments: safeToArray(arguments) }); };
|
||||
}
|
||||
|
||||
function handleExceptions() {
|
||||
|
|
|
@ -10,7 +10,7 @@ function entrypoint(name) {
|
|||
exports.base = [{
|
||||
name: 'vs/base/common/worker/simpleWorker',
|
||||
include: ['vs/editor/common/services/editorSimpleWorker'],
|
||||
prepend: ['vs/loader.js'],
|
||||
prepend: ['vs/loader.js', 'vs/nls.js'],
|
||||
append: ['vs/base/worker/workerMain'],
|
||||
dest: 'vs/base/worker/workerMain.js'
|
||||
}];
|
||||
|
|
|
@ -451,6 +451,8 @@ export interface IDimension {
|
|||
|
||||
export class Dimension implements IDimension {
|
||||
|
||||
static readonly None = new Dimension(0, 0);
|
||||
|
||||
constructor(
|
||||
public readonly width: number,
|
||||
public readonly height: number,
|
||||
|
@ -1398,7 +1400,12 @@ function toBinary(str: string): string {
|
|||
for (let i = 0; i < codeUnits.length; i++) {
|
||||
codeUnits[i] = str.charCodeAt(i);
|
||||
}
|
||||
return String.fromCharCode(...new Uint8Array(codeUnits.buffer));
|
||||
let binary = '';
|
||||
const uint8array = new Uint8Array(codeUnits.buffer);
|
||||
for (let i = 0; i < uint8array.length; i++) {
|
||||
binary += String.fromCharCode(uint8array[i]);
|
||||
}
|
||||
return binary;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,7 @@ import { isMacintosh } from 'vs/base/common/platform';
|
|||
import { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
|
||||
import { AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { isString } from 'vs/base/common/types';
|
||||
import { isFunction, isString } from 'vs/base/common/types';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
|
||||
export interface IIconLabelCreationOptions {
|
||||
|
@ -25,7 +25,7 @@ export interface IIconLabelCreationOptions {
|
|||
}
|
||||
|
||||
export interface IIconLabelMarkdownString {
|
||||
markdown: IMarkdownString | string | undefined | Promise<IMarkdownString | string | undefined>;
|
||||
markdown: IMarkdownString | string | undefined | (() => Promise<IMarkdownString | string | undefined>);
|
||||
markdownNotSupportedFallback: string | undefined;
|
||||
}
|
||||
|
||||
|
@ -191,23 +191,39 @@ export class IconLabel extends Disposable {
|
|||
}
|
||||
|
||||
private setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTMLElement, markdownTooltip: string | IIconLabelMarkdownString): void {
|
||||
htmlElement.setAttribute('title', '');
|
||||
htmlElement.removeAttribute('title');
|
||||
let tooltip = isString(markdownTooltip) ? markdownTooltip : markdownTooltip.markdown;
|
||||
let tooltip: () => Promise<string | IMarkdownString | undefined>;
|
||||
if (isString(markdownTooltip)) {
|
||||
tooltip = async () => markdownTooltip;
|
||||
} else if (isFunction(markdownTooltip.markdown)) {
|
||||
tooltip = markdownTooltip.markdown;
|
||||
} else {
|
||||
const markdown = markdownTooltip.markdown;
|
||||
tooltip = async () => markdown;
|
||||
}
|
||||
// Testing has indicated that on Windows and Linux 500 ms matches the native hovers most closely.
|
||||
// On Mac, the delay is 1500.
|
||||
const hoverDelay = isMacintosh ? 1500 : 500;
|
||||
let hoverOptions: IHoverDelegateOptions | undefined;
|
||||
let mouseX: number | undefined;
|
||||
let isHovering = false;
|
||||
function mouseOver(this: HTMLElement, e: MouseEvent): any {
|
||||
let isHovering = true;
|
||||
function mouseMove(this: HTMLElement, e: MouseEvent): any {
|
||||
mouseX = e.x;
|
||||
if (isHovering) {
|
||||
return;
|
||||
}
|
||||
function mouseLeaveOrDown(this: HTMLElement, e: MouseEvent): any {
|
||||
isHovering = false;
|
||||
mouseLeaveDisposable.dispose();
|
||||
mouseDownDisposable.dispose();
|
||||
}
|
||||
const mouseLeaveDisposable = domEvent(htmlElement, dom.EventType.MOUSE_LEAVE, true)(mouseLeaveOrDown.bind(htmlElement));
|
||||
const mouseDownDisposable = domEvent(htmlElement, dom.EventType.MOUSE_DOWN, true)(mouseLeaveOrDown.bind(htmlElement));
|
||||
isHovering = true;
|
||||
|
||||
function mouseMove(this: HTMLElement, e: MouseEvent): any {
|
||||
mouseX = e.x;
|
||||
}
|
||||
const mouseMoveDisposable = domEvent(htmlElement, dom.EventType.MOUSE_MOVE, true)(mouseMove.bind(htmlElement));
|
||||
setTimeout(async () => {
|
||||
if (isHovering && tooltip) {
|
||||
|
@ -217,7 +233,7 @@ export class IconLabel extends Disposable {
|
|||
targetElements: [this],
|
||||
dispose: () => { }
|
||||
};
|
||||
const resolvedTooltip = await tooltip;
|
||||
const resolvedTooltip = await tooltip();
|
||||
if (resolvedTooltip) {
|
||||
hoverOptions = {
|
||||
text: resolvedTooltip,
|
||||
|
@ -226,7 +242,8 @@ export class IconLabel extends Disposable {
|
|||
};
|
||||
}
|
||||
}
|
||||
if (hoverOptions) {
|
||||
// awaiting the tooltip could take a while. Make sure we're still hovering.
|
||||
if (hoverOptions && isHovering) {
|
||||
if (mouseX !== undefined) {
|
||||
(<IHoverDelegateTarget>hoverOptions.target).x = mouseX + 10;
|
||||
}
|
||||
|
@ -234,8 +251,6 @@ export class IconLabel extends Disposable {
|
|||
}
|
||||
}
|
||||
mouseMoveDisposable.dispose();
|
||||
mouseLeaveDisposable.dispose();
|
||||
mouseDownDisposable.dispose();
|
||||
}, hoverDelay);
|
||||
}
|
||||
const mouseOverDisposable = this._register(domEvent(htmlElement, dom.EventType.MOUSE_OVER, true)(mouseOver.bind(htmlElement)));
|
||||
|
|
|
@ -258,6 +258,10 @@ export class PagedList<T> implements IThemable, IDisposable {
|
|||
return this.list.getSelection();
|
||||
}
|
||||
|
||||
getSelectedElements(): T[] {
|
||||
return this.getSelection().map(i => this.model.get(i));
|
||||
}
|
||||
|
||||
layout(height?: number, width?: number): void {
|
||||
this.list.layout(height, width);
|
||||
}
|
||||
|
|
|
@ -1117,9 +1117,7 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
|
|||
expandOnlyOnTwistieClick = !!this.tree.expandOnlyOnTwistieClick;
|
||||
}
|
||||
|
||||
const clickedOnFocus = this.tree.getFocus()[0] === node.element;
|
||||
|
||||
if (expandOnlyOnTwistieClick && !onTwistie && e.browserEvent.detail !== 2 && !(clickedOnFocus && !node.collapsed)) {
|
||||
if (expandOnlyOnTwistieClick && !onTwistie && e.browserEvent.detail !== 2) {
|
||||
return super.onViewPointer(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -377,7 +377,8 @@ export class TernarySearchTree<K, V> {
|
|||
}
|
||||
|
||||
has(key: K): boolean {
|
||||
return !!this._getNode(key);
|
||||
const node = this._getNode(key);
|
||||
return !(node?.value === undefined && node?.mid === undefined);
|
||||
}
|
||||
|
||||
delete(key: K): void {
|
||||
|
|
|
@ -459,13 +459,13 @@ export function whenDeleted(path: string): Promise<void> {
|
|||
|
||||
export async function move(source: string, target: string): Promise<void> {
|
||||
if (source === target) {
|
||||
return Promise.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
async function updateMtime(path: string): Promise<void> {
|
||||
const stat = await lstat(path);
|
||||
if (stat.isDirectory() || stat.isSymbolicLink()) {
|
||||
return Promise.resolve(); // only for files
|
||||
return; // only for files
|
||||
}
|
||||
|
||||
const fd = await promisify(fs.open)(path, 'a');
|
||||
|
@ -510,7 +510,7 @@ export async function copy(source: string, target: string, copiedSourcesIn?: { [
|
|||
}
|
||||
|
||||
if (copiedSources[source]) {
|
||||
return Promise.resolve(); // escape when there are cycles (can happen with symlinks)
|
||||
return; // escape when there are cycles (can happen with symlinks)
|
||||
}
|
||||
|
||||
copiedSources[source] = true; // remember as copied
|
||||
|
|
|
@ -190,12 +190,11 @@ class ListElementRenderer implements IListRenderer<ListElement, IListElementTemp
|
|||
if (button.alwaysVisible) {
|
||||
cssClasses = cssClasses ? `${cssClasses} always-visible` : 'always-visible';
|
||||
}
|
||||
const action = new Action(`id-${index}`, '', cssClasses, true, () => {
|
||||
const action = new Action(`id-${index}`, '', cssClasses, true, async () => {
|
||||
element.fireButtonTriggered({
|
||||
button,
|
||||
item: element.item
|
||||
});
|
||||
return Promise.resolve();
|
||||
});
|
||||
action.tooltip = button.tooltip || '';
|
||||
return action;
|
||||
|
|
|
@ -200,9 +200,9 @@ export class Storage extends Disposable implements IStorage {
|
|||
return parseInt(value, 10);
|
||||
}
|
||||
|
||||
set(key: string, value: string | boolean | number | null | undefined): Promise<void> {
|
||||
async set(key: string, value: string | boolean | number | null | undefined): Promise<void> {
|
||||
if (this.state === StorageState.Closed) {
|
||||
return Promise.resolve(); // Return early if we are already closed
|
||||
return; // Return early if we are already closed
|
||||
}
|
||||
|
||||
// We remove the key for undefined/null values
|
||||
|
@ -216,7 +216,7 @@ export class Storage extends Disposable implements IStorage {
|
|||
// Return early if value already set
|
||||
const currentValue = this.cache.get(key);
|
||||
if (currentValue === valueStr) {
|
||||
return Promise.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update in cache and pending
|
||||
|
@ -231,15 +231,15 @@ export class Storage extends Disposable implements IStorage {
|
|||
return this.flushDelayer.trigger(() => this.flushPending());
|
||||
}
|
||||
|
||||
delete(key: string): Promise<void> {
|
||||
async delete(key: string): Promise<void> {
|
||||
if (this.state === StorageState.Closed) {
|
||||
return Promise.resolve(); // Return early if we are already closed
|
||||
return; // Return early if we are already closed
|
||||
}
|
||||
|
||||
// Remove from cache and add to pending
|
||||
const wasDeleted = this.cache.delete(key);
|
||||
if (!wasDeleted) {
|
||||
return Promise.resolve(); // Return early if value already deleted
|
||||
return; // Return early if value already deleted
|
||||
}
|
||||
|
||||
if (!this.pendingDeletes.has(key)) {
|
||||
|
@ -257,7 +257,7 @@ export class Storage extends Disposable implements IStorage {
|
|||
|
||||
async close(): Promise<void> {
|
||||
if (this.state === StorageState.Closed) {
|
||||
return Promise.resolve(); // return if already closed
|
||||
return; // return if already closed
|
||||
}
|
||||
|
||||
// Update state
|
||||
|
@ -282,9 +282,9 @@ export class Storage extends Disposable implements IStorage {
|
|||
return this.pendingInserts.size > 0 || this.pendingDeletes.size > 0;
|
||||
}
|
||||
|
||||
private flushPending(): Promise<void> {
|
||||
private async flushPending(): Promise<void> {
|
||||
if (!this.hasPending) {
|
||||
return Promise.resolve(); // return early if nothing to do
|
||||
return; // return early if nothing to do
|
||||
}
|
||||
|
||||
// Get pending data
|
||||
|
@ -305,9 +305,9 @@ export class Storage extends Disposable implements IStorage {
|
|||
});
|
||||
}
|
||||
|
||||
whenFlushed(): Promise<void> {
|
||||
async whenFlushed(): Promise<void> {
|
||||
if (!this.hasPending) {
|
||||
return Promise.resolve(); // return early if nothing to do
|
||||
return; // return early if nothing to do
|
||||
}
|
||||
|
||||
return new Promise(resolve => this.whenFlushedCallbacks.push(resolve));
|
||||
|
|
|
@ -73,8 +73,9 @@ suite('dom', () => {
|
|||
});
|
||||
|
||||
test('multibyteAwareBtoa', () => {
|
||||
assert.equal(dom.multibyteAwareBtoa('hello world'), dom.multibyteAwareBtoa('hello world'));
|
||||
assert.ok(dom.multibyteAwareBtoa('平仮名'));
|
||||
assert.ok(dom.multibyteAwareBtoa('hello world').length > 0);
|
||||
assert.ok(dom.multibyteAwareBtoa('平仮名').length > 0);
|
||||
assert.ok(dom.multibyteAwareBtoa(new Array(100000).fill('vs').join('')).length > 0); // https://github.com/microsoft/vscode/issues/112013
|
||||
});
|
||||
|
||||
suite('$', () => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { app, ipcMain, systemPreferences, contentTracing, protocol, BrowserWindo
|
|||
import { IProcessEnvironment, isWindows, isMacintosh, isLinux } from 'vs/base/common/platform';
|
||||
import { WindowsMainService } from 'vs/platform/windows/electron-main/windowsMainService';
|
||||
import { IWindowOpenable } from 'vs/platform/windows/common/windows';
|
||||
import { OpenContext } from 'vs/platform/windows/node/window';
|
||||
import { OpenContext } from 'vs/platform/windows/electron-main/window';
|
||||
import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
import { resolveShellEnv } from 'vs/code/node/shellEnv';
|
||||
import { IUpdateService } from 'vs/platform/update/common/update';
|
||||
|
@ -34,7 +34,6 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper
|
|||
import { getDelayedChannel, StaticRouter, createChannelReceiver, createChannelSender } from 'vs/base/parts/ipc/common/ipc';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { ProxyAuthHandler } from 'vs/code/electron-main/auth';
|
||||
import { ProxyAuthHandler2 } from 'vs/code/electron-main/auth2';
|
||||
import { FileProtocolHandler } from 'vs/code/electron-main/protocol';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
|
||||
|
@ -71,7 +70,7 @@ import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/ext
|
|||
import { ElectronExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/electron-main/extensionHostDebugIpc';
|
||||
import { INativeHostMainService, NativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
|
||||
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
|
||||
import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels';
|
||||
import { WebviewMainService } from 'vs/platform/webview/electron-main/webviewMainService';
|
||||
|
@ -454,12 +453,8 @@ export class CodeApplication extends Disposable {
|
|||
this._register(server);
|
||||
}
|
||||
|
||||
// Setup Auth Handler (TODO@ben remove old auth handler eventually)
|
||||
if (this.configurationService.getValue('window.enableExperimentalProxyLoginDialog') === false) {
|
||||
this._register(new ProxyAuthHandler());
|
||||
} else {
|
||||
this._register(appInstantiationService.createInstance(ProxyAuthHandler2));
|
||||
}
|
||||
// Setup Auth Handler
|
||||
this._register(appInstantiationService.createInstance(ProxyAuthHandler));
|
||||
|
||||
// Open Windows
|
||||
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient, fileProtocolHandler));
|
||||
|
@ -902,7 +897,12 @@ export class CodeApplication extends Disposable {
|
|||
this.lifecycleMainService.phase = LifecycleMainPhase.AfterWindowOpen;
|
||||
|
||||
// Remote Authorities
|
||||
this.handleRemoteAuthorities();
|
||||
protocol.registerHttpProtocol(Schemas.vscodeRemoteResource, (request, callback) => {
|
||||
callback({
|
||||
url: request.url.replace(/^vscode-remote-resource:/, 'http:'),
|
||||
method: request.method
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize update service
|
||||
const updateService = accessor.get(IUpdateService);
|
||||
|
@ -934,19 +934,11 @@ export class CodeApplication extends Disposable {
|
|||
'}'
|
||||
];
|
||||
const newArgvString = argvString.substring(0, argvString.length - 2).concat(',\n', additionalArgvContent.join('\n'));
|
||||
|
||||
await this.fileService.writeFile(this.environmentService.argvResource, VSBuffer.fromString(newArgvString));
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
private handleRemoteAuthorities(): void {
|
||||
protocol.registerHttpProtocol(Schemas.vscodeRemoteResource, (request, callback) => {
|
||||
callback({
|
||||
url: request.url.replace(/^vscode-remote-resource:/, 'http:'),
|
||||
method: request.method
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,18 +3,28 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { BrowserWindow, BrowserWindowConstructorOptions, app, AuthInfo, WebContents, Event as ElectronEvent } from 'electron';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { app, AuthInfo, WebContents, Event as ElectronEvent, AuthenticationResponseDetails } from 'electron';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
|
||||
import { IEncryptionMainService } from 'vs/platform/encryption/electron-main/encryptionMainService';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
interface ElectronAuthenticationResponseDetails extends AuthenticationResponseDetails {
|
||||
firstAuthAttempt?: boolean; // https://github.com/electron/electron/blob/84a42a050e7d45225e69df5bd2d2bf9f1037ea41/shell/browser/login_handler.cc#L70
|
||||
}
|
||||
|
||||
type LoginEvent = {
|
||||
event: ElectronEvent;
|
||||
webContents: WebContents;
|
||||
req: Request;
|
||||
authInfo: AuthInfo;
|
||||
cb: (username: string, password: string) => void;
|
||||
req: ElectronAuthenticationResponseDetails;
|
||||
|
||||
callback: (username?: string, password?: string) => void;
|
||||
};
|
||||
|
||||
type Credentials = {
|
||||
|
@ -22,81 +32,211 @@ type Credentials = {
|
|||
password: string;
|
||||
};
|
||||
|
||||
enum ProxyAuthState {
|
||||
|
||||
/**
|
||||
* Initial state: we will try to use stored credentials
|
||||
* first to reply to the auth challenge.
|
||||
*/
|
||||
Initial = 1,
|
||||
|
||||
/**
|
||||
* We used stored credentials and are still challenged,
|
||||
* so we will show a login dialog next.
|
||||
*/
|
||||
StoredCredentialsUsed,
|
||||
|
||||
/**
|
||||
* Finally, if we showed a login dialog already, we will
|
||||
* not show any more login dialogs until restart to reduce
|
||||
* the UI noise.
|
||||
*/
|
||||
LoginDialogShown
|
||||
}
|
||||
|
||||
export class ProxyAuthHandler extends Disposable {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
private static PROXY_CREDENTIALS_SERVICE_KEY = `${product.urlProtocol}.proxy-credentials`;
|
||||
|
||||
private retryCount = 0;
|
||||
private pendingProxyResolve: Promise<Credentials | undefined> | undefined = undefined;
|
||||
|
||||
constructor() {
|
||||
private state = ProxyAuthState.Initial;
|
||||
|
||||
private sessionCredentials: Credentials | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
|
||||
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
|
||||
@IEncryptionMainService private readonly encryptionMainService: IEncryptionMainService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
const onLogin = Event.fromNodeEventEmitter<LoginEvent>(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb }));
|
||||
const onLogin = Event.fromNodeEventEmitter<LoginEvent>(app, 'login', (event: ElectronEvent, webContents: WebContents, req: ElectronAuthenticationResponseDetails, authInfo: AuthInfo, callback) => ({ event, webContents, req, authInfo, callback }));
|
||||
this._register(onLogin(this.onLogin, this));
|
||||
}
|
||||
|
||||
private onLogin({ event, authInfo, cb }: LoginEvent): void {
|
||||
private async onLogin({ event, authInfo, req, callback }: LoginEvent): Promise<void> {
|
||||
if (!authInfo.isProxy) {
|
||||
return;
|
||||
return; // only for proxy
|
||||
}
|
||||
|
||||
if (this.retryCount++ > 1) {
|
||||
return;
|
||||
if (!this.pendingProxyResolve && this.state === ProxyAuthState.LoginDialogShown && req.firstAuthAttempt) {
|
||||
this.logService.trace('auth#onLogin (proxy) - exit - proxy dialog already shown');
|
||||
|
||||
return; // only one dialog per session at max (except when firstAuthAttempt: false which indicates a login problem)
|
||||
}
|
||||
|
||||
// Signal we handle this event on our own, otherwise
|
||||
// Electron will ignore our provided credentials.
|
||||
event.preventDefault();
|
||||
|
||||
const opts: BrowserWindowConstructorOptions = {
|
||||
alwaysOnTop: true,
|
||||
skipTaskbar: true,
|
||||
resizable: false,
|
||||
width: 450,
|
||||
height: 225,
|
||||
show: true,
|
||||
title: 'VS Code',
|
||||
webPreferences: {
|
||||
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js', require).fsPath,
|
||||
sandbox: true,
|
||||
contextIsolation: true,
|
||||
enableWebSQL: false,
|
||||
enableRemoteModule: false,
|
||||
spellcheck: false,
|
||||
devTools: false
|
||||
}
|
||||
};
|
||||
let credentials: Credentials | undefined = undefined;
|
||||
if (!this.pendingProxyResolve) {
|
||||
this.logService.trace('auth#onLogin (proxy) - no pending proxy handling found, starting new');
|
||||
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow) {
|
||||
opts.parent = focusedWindow;
|
||||
opts.modal = true;
|
||||
this.pendingProxyResolve = this.resolveProxyCredentials(authInfo);
|
||||
try {
|
||||
credentials = await this.pendingProxyResolve;
|
||||
} finally {
|
||||
this.pendingProxyResolve = undefined;
|
||||
}
|
||||
} else {
|
||||
this.logService.trace('auth#onLogin (proxy) - pending proxy handling found');
|
||||
|
||||
credentials = await this.pendingProxyResolve;
|
||||
}
|
||||
|
||||
const win = new BrowserWindow(opts);
|
||||
const windowUrl = FileAccess.asBrowserUri('vs/code/electron-sandbox/proxy/auth.html', require);
|
||||
const proxyUrl = `${authInfo.host}:${authInfo.port}`;
|
||||
const title = localize('authRequire', "Proxy Authentication Required");
|
||||
const message = localize('proxyauth', "The proxy {0} requires authentication.", proxyUrl);
|
||||
// According to Electron docs, it is fine to call back without
|
||||
// username or password to signal that the authentication was handled
|
||||
// by us, even though without having credentials received:
|
||||
//
|
||||
// > If `callback` is called without a username or password, the authentication
|
||||
// > request will be cancelled and the authentication error will be returned to the
|
||||
// > page.
|
||||
callback(credentials?.username, credentials?.password);
|
||||
}
|
||||
|
||||
const onWindowClose = () => cb('', '');
|
||||
win.on('close', onWindowClose);
|
||||
private async resolveProxyCredentials(authInfo: AuthInfo): Promise<Credentials | undefined> {
|
||||
this.logService.trace('auth#resolveProxyCredentials (proxy) - enter');
|
||||
|
||||
win.setMenu(null);
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
const data = { title, message };
|
||||
win.webContents.send('vscode:openProxyAuthDialog', data);
|
||||
});
|
||||
win.webContents.on('ipc-message', (event, channel, credentials: Credentials) => {
|
||||
if (channel === 'vscode:proxyAuthResponse') {
|
||||
const { username, password } = credentials;
|
||||
cb(username, password);
|
||||
win.removeListener('close', onWindowClose);
|
||||
win.close();
|
||||
try {
|
||||
const credentials = await this.doResolveProxyCredentials(authInfo);
|
||||
if (credentials) {
|
||||
this.logService.trace('auth#resolveProxyCredentials (proxy) - got credentials');
|
||||
|
||||
return credentials;
|
||||
} else {
|
||||
this.logService.trace('auth#resolveProxyCredentials (proxy) - did not get credentials');
|
||||
}
|
||||
} finally {
|
||||
this.logService.trace('auth#resolveProxyCredentials (proxy) - exit');
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async doResolveProxyCredentials(authInfo: AuthInfo): Promise<Credentials | undefined> {
|
||||
this.logService.trace('auth#doResolveProxyCredentials - enter', authInfo);
|
||||
|
||||
// Compute a hash over the authentication info to be used
|
||||
// with the credentials store to return the right credentials
|
||||
// given the properties of the auth request
|
||||
// (see https://github.com/microsoft/vscode/issues/109497)
|
||||
const authInfoHash = String(hash({ scheme: authInfo.scheme, host: authInfo.host, port: authInfo.port }));
|
||||
|
||||
// Find any previously stored credentials
|
||||
let storedUsername: string | undefined = undefined;
|
||||
let storedPassword: string | undefined = undefined;
|
||||
try {
|
||||
const encryptedSerializedProxyCredentials = await this.nativeHostMainService.getPassword(undefined, ProxyAuthHandler.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash);
|
||||
if (encryptedSerializedProxyCredentials) {
|
||||
const credentials: Credentials = JSON.parse(await this.encryptionMainService.decrypt(encryptedSerializedProxyCredentials));
|
||||
|
||||
storedUsername = credentials.username;
|
||||
storedPassword = credentials.password;
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error); // handle errors by asking user for login via dialog
|
||||
}
|
||||
|
||||
// Reply with stored credentials unless we used them already.
|
||||
// In that case we need to show a login dialog again because
|
||||
// they seem invalid.
|
||||
if (this.state !== ProxyAuthState.StoredCredentialsUsed && typeof storedUsername === 'string' && typeof storedPassword === 'string') {
|
||||
this.logService.trace('auth#doResolveProxyCredentials (proxy) - exit - found stored credentials to use');
|
||||
this.state = ProxyAuthState.StoredCredentialsUsed;
|
||||
|
||||
return { username: storedUsername, password: storedPassword };
|
||||
}
|
||||
|
||||
// Find suitable window to show dialog: prefer to show it in the
|
||||
// active window because any other network request will wait on
|
||||
// the credentials and we want the user to present the dialog.
|
||||
const window = this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow();
|
||||
if (!window) {
|
||||
this.logService.trace('auth#doResolveProxyCredentials (proxy) - exit - no opened window found to show dialog in');
|
||||
|
||||
return undefined; // unexpected
|
||||
}
|
||||
|
||||
this.logService.trace(`auth#doResolveProxyCredentials (proxy) - asking window ${window.id} to handle proxy login`);
|
||||
|
||||
// Open proxy dialog
|
||||
const payload = {
|
||||
authInfo,
|
||||
username: this.sessionCredentials?.username ?? storedUsername, // prefer to show already used username (if any) over stored
|
||||
password: this.sessionCredentials?.password ?? storedPassword, // prefer to show already used password (if any) over stored
|
||||
replyChannel: `vscode:proxyAuthResponse:${generateUuid()}`
|
||||
};
|
||||
window.sendWhenReady('vscode:openProxyAuthenticationDialog', CancellationToken.None, payload);
|
||||
this.state = ProxyAuthState.LoginDialogShown;
|
||||
|
||||
// Handle reply
|
||||
const loginDialogCredentials = await new Promise<Credentials | undefined>(resolve => {
|
||||
const proxyAuthResponseHandler = async (event: ElectronEvent, channel: string, reply: Credentials & { remember: boolean } | undefined /* canceled */) => {
|
||||
if (channel === payload.replyChannel) {
|
||||
this.logService.trace(`auth#doResolveProxyCredentials - exit - received credentials from window ${window.id}`);
|
||||
window.win.webContents.off('ipc-message', proxyAuthResponseHandler);
|
||||
|
||||
// We got credentials from the window
|
||||
if (reply) {
|
||||
const credentials: Credentials = { username: reply.username, password: reply.password };
|
||||
|
||||
// Update stored credentials based on `remember` flag
|
||||
try {
|
||||
if (reply.remember) {
|
||||
const encryptedSerializedCredentials = await this.encryptionMainService.encrypt(JSON.stringify(credentials));
|
||||
await this.nativeHostMainService.setPassword(undefined, ProxyAuthHandler.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash, encryptedSerializedCredentials);
|
||||
} else {
|
||||
await this.nativeHostMainService.deletePassword(undefined, ProxyAuthHandler.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error); // handle gracefully
|
||||
}
|
||||
|
||||
resolve({ username: credentials.username, password: credentials.password });
|
||||
}
|
||||
|
||||
// We did not get any credentials from the window (e.g. cancelled)
|
||||
else {
|
||||
resolve(undefined);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.win.webContents.on('ipc-message', proxyAuthResponseHandler);
|
||||
});
|
||||
win.loadURL(windowUrl.toString(true));
|
||||
|
||||
// Remember credentials for the session in case
|
||||
// the credentials are wrong and we show the dialog
|
||||
// again
|
||||
this.sessionCredentials = loginDialogCredentials;
|
||||
|
||||
return loginDialogCredentials;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,242 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { app, AuthInfo, WebContents, Event as ElectronEvent, AuthenticationResponseDetails } from 'electron';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
|
||||
import { IEncryptionMainService } from 'vs/platform/encryption/electron-main/encryptionMainService';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
interface ElectronAuthenticationResponseDetails extends AuthenticationResponseDetails {
|
||||
firstAuthAttempt?: boolean; // https://github.com/electron/electron/blob/84a42a050e7d45225e69df5bd2d2bf9f1037ea41/shell/browser/login_handler.cc#L70
|
||||
}
|
||||
|
||||
type LoginEvent = {
|
||||
event: ElectronEvent;
|
||||
authInfo: AuthInfo;
|
||||
req: ElectronAuthenticationResponseDetails;
|
||||
|
||||
callback: (username?: string, password?: string) => void;
|
||||
};
|
||||
|
||||
type Credentials = {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
enum ProxyAuthState {
|
||||
|
||||
/**
|
||||
* Initial state: we will try to use stored credentials
|
||||
* first to reply to the auth challenge.
|
||||
*/
|
||||
Initial = 1,
|
||||
|
||||
/**
|
||||
* We used stored credentials and are still challenged,
|
||||
* so we will show a login dialog next.
|
||||
*/
|
||||
StoredCredentialsUsed,
|
||||
|
||||
/**
|
||||
* Finally, if we showed a login dialog already, we will
|
||||
* not show any more login dialogs until restart to reduce
|
||||
* the UI noise.
|
||||
*/
|
||||
LoginDialogShown
|
||||
}
|
||||
|
||||
export class ProxyAuthHandler2 extends Disposable {
|
||||
|
||||
private static PROXY_CREDENTIALS_SERVICE_KEY = `${product.urlProtocol}.proxy-credentials`;
|
||||
|
||||
private pendingProxyResolve: Promise<Credentials | undefined> | undefined = undefined;
|
||||
|
||||
private state = ProxyAuthState.Initial;
|
||||
|
||||
private sessionCredentials: Credentials | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
|
||||
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
|
||||
@IEncryptionMainService private readonly encryptionMainService: IEncryptionMainService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
const onLogin = Event.fromNodeEventEmitter<LoginEvent>(app, 'login', (event: ElectronEvent, webContents: WebContents, req: ElectronAuthenticationResponseDetails, authInfo: AuthInfo, callback) => ({ event, webContents, req, authInfo, callback }));
|
||||
this._register(onLogin(this.onLogin, this));
|
||||
}
|
||||
|
||||
private async onLogin({ event, authInfo, req, callback }: LoginEvent): Promise<void> {
|
||||
if (!authInfo.isProxy) {
|
||||
return; // only for proxy
|
||||
}
|
||||
|
||||
if (!this.pendingProxyResolve && this.state === ProxyAuthState.LoginDialogShown && req.firstAuthAttempt) {
|
||||
this.logService.trace('auth#onLogin (proxy) - exit - proxy dialog already shown');
|
||||
|
||||
return; // only one dialog per session at max (except when firstAuthAttempt: false which indicates a login problem)
|
||||
}
|
||||
|
||||
// Signal we handle this event on our own, otherwise
|
||||
// Electron will ignore our provided credentials.
|
||||
event.preventDefault();
|
||||
|
||||
let credentials: Credentials | undefined = undefined;
|
||||
if (!this.pendingProxyResolve) {
|
||||
this.logService.trace('auth#onLogin (proxy) - no pending proxy handling found, starting new');
|
||||
|
||||
this.pendingProxyResolve = this.resolveProxyCredentials(authInfo);
|
||||
try {
|
||||
credentials = await this.pendingProxyResolve;
|
||||
} finally {
|
||||
this.pendingProxyResolve = undefined;
|
||||
}
|
||||
} else {
|
||||
this.logService.trace('auth#onLogin (proxy) - pending proxy handling found');
|
||||
|
||||
credentials = await this.pendingProxyResolve;
|
||||
}
|
||||
|
||||
// According to Electron docs, it is fine to call back without
|
||||
// username or password to signal that the authentication was handled
|
||||
// by us, even though without having credentials received:
|
||||
//
|
||||
// > If `callback` is called without a username or password, the authentication
|
||||
// > request will be cancelled and the authentication error will be returned to the
|
||||
// > page.
|
||||
callback(credentials?.username, credentials?.password);
|
||||
}
|
||||
|
||||
private async resolveProxyCredentials(authInfo: AuthInfo): Promise<Credentials | undefined> {
|
||||
this.logService.trace('auth#resolveProxyCredentials (proxy) - enter');
|
||||
|
||||
try {
|
||||
const credentials = await this.doResolveProxyCredentials(authInfo);
|
||||
if (credentials) {
|
||||
this.logService.trace('auth#resolveProxyCredentials (proxy) - got credentials');
|
||||
|
||||
return credentials;
|
||||
} else {
|
||||
this.logService.trace('auth#resolveProxyCredentials (proxy) - did not get credentials');
|
||||
}
|
||||
} finally {
|
||||
this.logService.trace('auth#resolveProxyCredentials (proxy) - exit');
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async doResolveProxyCredentials(authInfo: AuthInfo): Promise<Credentials | undefined> {
|
||||
this.logService.trace('auth#doResolveProxyCredentials - enter', authInfo);
|
||||
|
||||
// Compute a hash over the authentication info to be used
|
||||
// with the credentials store to return the right credentials
|
||||
// given the properties of the auth request
|
||||
// (see https://github.com/microsoft/vscode/issues/109497)
|
||||
const authInfoHash = String(hash({ scheme: authInfo.scheme, host: authInfo.host, port: authInfo.port }));
|
||||
|
||||
// Find any previously stored credentials
|
||||
let storedUsername: string | undefined = undefined;
|
||||
let storedPassword: string | undefined = undefined;
|
||||
try {
|
||||
const encryptedSerializedProxyCredentials = await this.nativeHostMainService.getPassword(undefined, ProxyAuthHandler2.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash);
|
||||
if (encryptedSerializedProxyCredentials) {
|
||||
const credentials: Credentials = JSON.parse(await this.encryptionMainService.decrypt(encryptedSerializedProxyCredentials));
|
||||
|
||||
storedUsername = credentials.username;
|
||||
storedPassword = credentials.password;
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error); // handle errors by asking user for login via dialog
|
||||
}
|
||||
|
||||
// Reply with stored credentials unless we used them already.
|
||||
// In that case we need to show a login dialog again because
|
||||
// they seem invalid.
|
||||
if (this.state !== ProxyAuthState.StoredCredentialsUsed && typeof storedUsername === 'string' && typeof storedPassword === 'string') {
|
||||
this.logService.trace('auth#doResolveProxyCredentials (proxy) - exit - found stored credentials to use');
|
||||
this.state = ProxyAuthState.StoredCredentialsUsed;
|
||||
|
||||
return { username: storedUsername, password: storedPassword };
|
||||
}
|
||||
|
||||
// Find suitable window to show dialog: prefer to show it in the
|
||||
// active window because any other network request will wait on
|
||||
// the credentials and we want the user to present the dialog.
|
||||
const window = this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow();
|
||||
if (!window) {
|
||||
this.logService.trace('auth#doResolveProxyCredentials (proxy) - exit - no opened window found to show dialog in');
|
||||
|
||||
return undefined; // unexpected
|
||||
}
|
||||
|
||||
this.logService.trace(`auth#doResolveProxyCredentials (proxy) - asking window ${window.id} to handle proxy login`);
|
||||
|
||||
// Open proxy dialog
|
||||
const payload = {
|
||||
authInfo,
|
||||
username: this.sessionCredentials?.username ?? storedUsername, // prefer to show already used username (if any) over stored
|
||||
password: this.sessionCredentials?.password ?? storedPassword, // prefer to show already used password (if any) over stored
|
||||
replyChannel: `vscode:proxyAuthResponse:${generateUuid()}`
|
||||
};
|
||||
window.sendWhenReady('vscode:openProxyAuthenticationDialog', CancellationToken.None, payload);
|
||||
this.state = ProxyAuthState.LoginDialogShown;
|
||||
|
||||
// Handle reply
|
||||
const loginDialogCredentials = await new Promise<Credentials | undefined>(resolve => {
|
||||
const proxyAuthResponseHandler = async (event: ElectronEvent, channel: string, reply: Credentials & { remember: boolean } | undefined /* canceled */) => {
|
||||
if (channel === payload.replyChannel) {
|
||||
this.logService.trace(`auth#doResolveProxyCredentials - exit - received credentials from window ${window.id}`);
|
||||
window.win.webContents.off('ipc-message', proxyAuthResponseHandler);
|
||||
|
||||
// We got credentials from the window
|
||||
if (reply) {
|
||||
const credentials: Credentials = { username: reply.username, password: reply.password };
|
||||
|
||||
// Update stored credentials based on `remember` flag
|
||||
try {
|
||||
if (reply.remember) {
|
||||
const encryptedSerializedCredentials = await this.encryptionMainService.encrypt(JSON.stringify(credentials));
|
||||
await this.nativeHostMainService.setPassword(undefined, ProxyAuthHandler2.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash, encryptedSerializedCredentials);
|
||||
} else {
|
||||
await this.nativeHostMainService.deletePassword(undefined, ProxyAuthHandler2.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error); // handle gracefully
|
||||
}
|
||||
|
||||
resolve({ username: credentials.username, password: credentials.password });
|
||||
}
|
||||
|
||||
// We did not get any credentials from the window (e.g. cancelled)
|
||||
else {
|
||||
resolve(undefined);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.win.webContents.on('ipc-message', proxyAuthResponseHandler);
|
||||
});
|
||||
|
||||
// Remember credentials for the session in case
|
||||
// the credentials are wrong and we show the dialog
|
||||
// again
|
||||
this.sessionCredentials = loginDialogCredentials;
|
||||
|
||||
return loginDialogCredentials;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
import 'vs/platform/update/common/update.config.contribution';
|
||||
import { app, dialog } from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import { unlinkSync } from 'fs';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isWindows, IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { parseMainProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper';
|
||||
|
@ -29,7 +30,6 @@ import { ConfigurationService } from 'vs/platform/configuration/common/configura
|
|||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { RequestMainService } from 'vs/platform/request/electron-main/requestMainService';
|
||||
import { CodeApplication } from 'vs/code/electron-main/app';
|
||||
import { localize } from 'vs/nls';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
||||
|
@ -256,7 +256,7 @@ class CodeMain {
|
|||
// let's delete it, since we can't connect to it and then
|
||||
// retry the whole thing
|
||||
try {
|
||||
fs.unlinkSync(environmentService.mainIPCHandle);
|
||||
unlinkSync(environmentService.mainIPCHandle);
|
||||
} catch (error) {
|
||||
logService.warn('Could not delete obsolete instance handle', error);
|
||||
|
||||
|
|
|
@ -17,12 +17,11 @@ import { FileAccess } from 'vs/base/common/network';
|
|||
|
||||
export class SharedProcess implements ISharedProcess {
|
||||
|
||||
private barrier = new Barrier();
|
||||
private readonly barrier = new Barrier();
|
||||
private readonly _whenReady: Promise<void>;
|
||||
|
||||
private window: BrowserWindow | null = null;
|
||||
|
||||
private readonly _whenReady: Promise<void>;
|
||||
|
||||
constructor(
|
||||
private readonly machineId: string,
|
||||
private userEnv: NodeJS.ProcessEnv,
|
||||
|
@ -52,6 +51,7 @@ export class SharedProcess implements ISharedProcess {
|
|||
disableBlinkFeatures: 'Auxclick' // do NOT change, allows us to identify this window as shared-process in the process explorer
|
||||
}
|
||||
});
|
||||
|
||||
const config = {
|
||||
appRoot: this.environmentService.appRoot,
|
||||
machineId: this.machineId,
|
||||
|
@ -110,7 +110,8 @@ export class SharedProcess implements ISharedProcess {
|
|||
}, 0);
|
||||
});
|
||||
|
||||
return new Promise<void>(c => {
|
||||
return new Promise<void>(resolve => {
|
||||
|
||||
// send payload once shared process is ready to receive it
|
||||
disposables.add(Event.once(Event.fromNodeEventEmitter(ipcMain, 'vscode:shared-process->electron-main=ready-for-payload', ({ sender }: { sender: WebContents }) => sender))(sender => {
|
||||
sender.send('vscode:electron-main->shared-process=payload', {
|
||||
|
@ -125,7 +126,7 @@ export class SharedProcess implements ISharedProcess {
|
|||
disposables.add(toDisposable(() => sender.send('vscode:electron-main->shared-process=exit')));
|
||||
|
||||
// complete IPC-ready promise when shared process signals this to us
|
||||
ipcMain.once('vscode:shared-process->electron-main=ipc-ready', () => c(undefined));
|
||||
ipcMain.once('vscode:shared-process->electron-main=ipc-ready', () => resolve(undefined));
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
@ -28,7 +28,7 @@ import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/commo
|
|||
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
|
@ -544,8 +544,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
|
||||
|
@ -648,6 +648,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||
this.currentMenuBarVisibility = newMenuBarVisibility;
|
||||
this.setMenuBarVisibility(newMenuBarVisibility);
|
||||
}
|
||||
|
||||
// Do not set to empty configuration at startup if setting is empty to not override configuration through CLI options:
|
||||
const env = process.env;
|
||||
let newHttpProxy = (this.configurationService.getValue<string>('http.proxy') || '').trim()
|
||||
|
@ -780,6 +781,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||
windowConfiguration.windowId = this._win.id;
|
||||
windowConfiguration.sessionId = `window:${this._win.id}`;
|
||||
windowConfiguration.logLevel = this.logService.getLevel();
|
||||
windowConfiguration.logsPath = this.environmentService.logsPath;
|
||||
|
||||
// Set zoomlevel
|
||||
const windowConfig = this.configurationService.getValue<IWindowSettings | undefined>('window');
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", system-ui, "Ubuntu", "Droid Sans", sans-serif;
|
||||
font-size: 10pt;
|
||||
background-color: #F3F3F3;
|
||||
}
|
||||
|
||||
#main {
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
font-size: 16px;
|
||||
background-color: #555;
|
||||
color: #f0f0f0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#form {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#username,
|
||||
#password {
|
||||
padding: 6px 10px;
|
||||
font-size: 12px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#buttons {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", system-ui, "Ubuntu", "Droid Sans", sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 id="title"></h1>
|
||||
<section id="main">
|
||||
<p id="message"></p>
|
||||
<form id="form">
|
||||
<p><input type="text" id="username" placeholder="Username" required /></p>
|
||||
<p><input type="password" id="password" placeholder="Password" required /></p>
|
||||
<p id="buttons">
|
||||
<input id="ok" type="submit" value="OK" />
|
||||
<input id="cancel" type="button" value="Cancel" />
|
||||
</p>
|
||||
</form>
|
||||
</section>
|
||||
</body>
|
||||
|
||||
<script src="auth.js"></script>
|
||||
|
||||
</html>
|
|
@ -1,48 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { ipcRenderer } = window.vscode;
|
||||
|
||||
function promptForCredentials(data) {
|
||||
return new Promise((c, e) => {
|
||||
const $title = document.getElementById('title');
|
||||
const $username = document.getElementById('username');
|
||||
const $password = document.getElementById('password');
|
||||
const $form = document.getElementById('form');
|
||||
const $cancel = document.getElementById('cancel');
|
||||
const $message = document.getElementById('message');
|
||||
|
||||
function submit() {
|
||||
c({ username: $username.value, password: $password.value });
|
||||
return false;
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
c({ username: '', password: '' });
|
||||
return false;
|
||||
}
|
||||
|
||||
$form.addEventListener('submit', submit);
|
||||
$cancel.addEventListener('click', cancel);
|
||||
|
||||
document.body.addEventListener('keydown', function (e) {
|
||||
switch (e.keyCode) {
|
||||
case 27: e.preventDefault(); e.stopPropagation(); return cancel();
|
||||
case 13: e.preventDefault(); e.stopPropagation(); return submit();
|
||||
}
|
||||
});
|
||||
|
||||
$title.textContent = data.title;
|
||||
$message.textContent = data.message;
|
||||
$username.focus();
|
||||
});
|
||||
}
|
||||
|
||||
ipcRenderer.on('vscode:openProxyAuthDialog', async (event, data) => {
|
||||
const response = await promptForCredentials(data);
|
||||
ipcRenderer.send('vscode:proxyAuthResponse', response);
|
||||
});
|
|
@ -276,6 +276,7 @@ export class TextAreaHandler extends ViewPart {
|
|||
this.textArea.setClassName(`inputarea ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME} ime-input`);
|
||||
|
||||
this._viewController.compositionStart();
|
||||
this._context.model.onCompositionStart();
|
||||
}));
|
||||
|
||||
this._register(this._textAreaInput.onCompositionUpdate((e: ICompositionData) => {
|
||||
|
@ -297,6 +298,7 @@ export class TextAreaHandler extends ViewPart {
|
|||
|
||||
this.textArea.setClassName(`inputarea ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`);
|
||||
this._viewController.compositionEnd();
|
||||
this._context.model.onCompositionEnd();
|
||||
}));
|
||||
|
||||
this._register(this._textAreaInput.onFocus(() => {
|
||||
|
|
|
@ -684,10 +684,15 @@ export interface ICodeEditor extends editorCommon.IEditor {
|
|||
executeCommand(source: string | null | undefined, command: editorCommon.ICommand): void;
|
||||
|
||||
/**
|
||||
* Push an "undo stop" in the undo-redo stack.
|
||||
* Create an "undo stop" in the undo-redo stack.
|
||||
*/
|
||||
pushUndoStop(): boolean;
|
||||
|
||||
/**
|
||||
* Remove the "undo stop" in the undo-redo stack.
|
||||
*/
|
||||
popUndoStop(): boolean;
|
||||
|
||||
/**
|
||||
* Execute edits on the editor.
|
||||
* The edits will land on the undo-redo stack, but no "undo stop" will be pushed.
|
||||
|
|
|
@ -69,6 +69,7 @@ export interface IBulkEditOptions {
|
|||
progress?: IProgress<IProgressStep>;
|
||||
token?: CancellationToken;
|
||||
showPreview?: boolean;
|
||||
suppressPreview?: boolean;
|
||||
label?: string;
|
||||
quotableLabel?: string;
|
||||
undoRedoSource?: UndoRedoSource;
|
||||
|
|
|
@ -237,6 +237,7 @@ class MinimapLayout {
|
|||
options: MinimapOptions,
|
||||
viewportStartLineNumber: number,
|
||||
viewportEndLineNumber: number,
|
||||
viewportStartLineNumberVerticalOffset: number,
|
||||
viewportHeight: number,
|
||||
viewportContainsWhitespaceGaps: boolean,
|
||||
lineCount: number,
|
||||
|
@ -331,7 +332,8 @@ class MinimapLayout {
|
|||
}
|
||||
|
||||
const endLineNumber = Math.min(lineCount, startLineNumber + minimapLinesFitting - 1);
|
||||
const sliderTopAligned = (scrollTop / lineHeight - startLineNumber + 1) * minimapLineHeight / pixelRatio;
|
||||
const partialLine = (scrollTop - viewportStartLineNumberVerticalOffset) / lineHeight;
|
||||
const sliderTopAligned = (viewportStartLineNumber - startLineNumber + partialLine) * minimapLineHeight / pixelRatio;
|
||||
|
||||
return new MinimapLayout(scrollTop, scrollHeight, true, computedSliderRatio, sliderTopAligned, sliderHeight, startLineNumber, endLineNumber);
|
||||
}
|
||||
|
@ -505,6 +507,7 @@ interface IMinimapRenderingContext {
|
|||
|
||||
readonly viewportStartLineNumber: number;
|
||||
readonly viewportEndLineNumber: number;
|
||||
readonly viewportStartLineNumberVerticalOffset: number;
|
||||
|
||||
readonly scrollTop: number;
|
||||
readonly scrollLeft: number;
|
||||
|
@ -891,6 +894,7 @@ export class Minimap extends ViewPart implements IMinimapModel {
|
|||
|
||||
viewportStartLineNumber: viewportStartLineNumber,
|
||||
viewportEndLineNumber: viewportEndLineNumber,
|
||||
viewportStartLineNumberVerticalOffset: ctx.getVerticalOffsetForLineNumber(viewportStartLineNumber),
|
||||
|
||||
scrollTop: ctx.scrollTop,
|
||||
scrollLeft: ctx.scrollLeft,
|
||||
|
@ -1344,6 +1348,7 @@ class InnerMinimap extends Disposable {
|
|||
this._model.options,
|
||||
renderingCtx.viewportStartLineNumber,
|
||||
renderingCtx.viewportEndLineNumber,
|
||||
renderingCtx.viewportStartLineNumberVerticalOffset,
|
||||
renderingCtx.viewportHeight,
|
||||
renderingCtx.viewportContainsWhitespaceGaps,
|
||||
this._model.getLineCount(),
|
||||
|
|
|
@ -25,6 +25,7 @@ export class ViewCursors extends ViewPart {
|
|||
private _cursorStyle: TextEditorCursorStyle;
|
||||
private _cursorSmoothCaretAnimation: boolean;
|
||||
private _selectionIsEmpty: boolean;
|
||||
private _isComposingInput: boolean;
|
||||
|
||||
private _isVisible: boolean;
|
||||
|
||||
|
@ -49,6 +50,7 @@ export class ViewCursors extends ViewPart {
|
|||
this._cursorStyle = options.get(EditorOption.cursorStyle);
|
||||
this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation);
|
||||
this._selectionIsEmpty = true;
|
||||
this._isComposingInput = false;
|
||||
|
||||
this._isVisible = false;
|
||||
|
||||
|
@ -83,7 +85,16 @@ export class ViewCursors extends ViewPart {
|
|||
}
|
||||
|
||||
// --- begin event handlers
|
||||
|
||||
public onCompositionStart(e: viewEvents.ViewCompositionStartEvent): boolean {
|
||||
this._isComposingInput = true;
|
||||
this._updateBlinking();
|
||||
return true;
|
||||
}
|
||||
public onCompositionEnd(e: viewEvents.ViewCompositionEndEvent): boolean {
|
||||
this._isComposingInput = false;
|
||||
this._updateBlinking();
|
||||
return true;
|
||||
}
|
||||
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
|
||||
const options = this._context.configuration.options;
|
||||
|
||||
|
@ -195,6 +206,10 @@ export class ViewCursors extends ViewPart {
|
|||
// ---- blinking logic
|
||||
|
||||
private _getCursorBlinking(): TextEditorCursorBlinkingStyle {
|
||||
if (this._isComposingInput) {
|
||||
// avoid double cursors
|
||||
return TextEditorCursorBlinkingStyle.Hidden;
|
||||
}
|
||||
if (!this._editorHasFocus) {
|
||||
return TextEditorCursorBlinkingStyle.Hidden;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
|
|||
import { ICommandDelegate } from 'vs/editor/browser/view/viewController';
|
||||
import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl';
|
||||
import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';
|
||||
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, filterValidationDecorations, InDiffEditorState } from 'vs/editor/common/config/editorOptions';
|
||||
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, filterValidationDecorations } from 'vs/editor/common/config/editorOptions';
|
||||
import { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
|
@ -1122,6 +1122,18 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
return true;
|
||||
}
|
||||
|
||||
public popUndoStop(): boolean {
|
||||
if (!this._modelData) {
|
||||
return false;
|
||||
}
|
||||
if (this._configuration.options.get(EditorOption.readOnly)) {
|
||||
// read only editor => sorry!
|
||||
return false;
|
||||
}
|
||||
this._modelData.model.popStackElement();
|
||||
return true;
|
||||
}
|
||||
|
||||
public executeEdits(source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], endCursorState?: ICursorStateComputer | Selection[]): boolean {
|
||||
if (!this._modelData) {
|
||||
return false;
|
||||
|
@ -1774,7 +1786,7 @@ class EditorContextKeysManager extends Disposable {
|
|||
|
||||
this._editorTabMovesFocus.set(options.get(EditorOption.tabFocusMode));
|
||||
this._editorReadonly.set(options.get(EditorOption.readOnly));
|
||||
this._inDiffEditor.set(options.get(EditorOption.inDiffEditor) !== InDiffEditorState.None);
|
||||
this._inDiffEditor.set(options.get(EditorOption.inDiffEditor));
|
||||
this._editorColumnSelection.set(options.get(EditorOption.columnSelection));
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser';
|
|||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { DiffReview } from 'vs/editor/browser/widget/diffReview';
|
||||
import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, EditorOption, EditorOptions, EditorFontLigatures, stringSet as validateStringSetOption, boolean as validateBooleanOption, InDiffEditorState } from 'vs/editor/common/config/editorOptions';
|
||||
import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, EditorOption, EditorOptions, EditorFontLigatures, stringSet as validateStringSetOption, boolean as validateBooleanOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
|
@ -155,8 +155,8 @@ class VisualEditorState {
|
|||
let DIFF_EDITOR_ID = 0;
|
||||
|
||||
|
||||
const diffInsertIcon = registerIcon('diff-insert', Codicon.add, nls.localize('diffInsertIcon', 'Line decoration for inserts in the diff editor'));
|
||||
const diffRemoveIcon = registerIcon('diff-remove', Codicon.remove, nls.localize('diffRemoveIcon', 'Line decoration for removals in the diff editor'));
|
||||
const diffInsertIcon = registerIcon('diff-insert', Codicon.add, nls.localize('diffInsertIcon', 'Line decoration for inserts in the diff editor.'));
|
||||
const diffRemoveIcon = registerIcon('diff-remove', Codicon.remove, nls.localize('diffRemoveIcon', 'Line decoration for removals in the diff editor.'));
|
||||
const ttPolicy = window.trustedTypes?.createPolicy('diffEditorWidget', { createHTML: value => value });
|
||||
|
||||
export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffEditor {
|
||||
|
@ -212,8 +212,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
|||
private _maxComputationTime: number;
|
||||
private _renderIndicators: boolean;
|
||||
private _enableSplitViewResizing: boolean;
|
||||
private _wordWrap: 'off' | 'on' | 'wordWrapColumn' | 'bounded' | undefined;
|
||||
private _wordWrapMinified: boolean | undefined;
|
||||
private _strategy!: DiffEditorWidgetStyle;
|
||||
|
||||
private readonly _updateDecorationsRunner: RunOnceScheduler;
|
||||
|
@ -255,9 +253,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
|||
this._domElement = domElement;
|
||||
options = options || {};
|
||||
|
||||
this._wordWrap = options.wordWrap;
|
||||
this._wordWrapMinified = options.wordWrapMinified;
|
||||
|
||||
// renderSideBySide
|
||||
this._renderSideBySide = true;
|
||||
if (typeof options.renderSideBySide !== 'undefined') {
|
||||
|
@ -685,9 +680,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
|||
|
||||
public updateOptions(newOptions: IDiffEditorOptions): void {
|
||||
|
||||
this._wordWrap = typeof newOptions.wordWrap !== 'undefined' ? newOptions.wordWrap : this._wordWrap;
|
||||
this._wordWrapMinified = typeof newOptions.wordWrapMinified !== 'undefined' ? newOptions.wordWrapMinified : this._wordWrapMinified;
|
||||
|
||||
// Handle side by side
|
||||
let renderSideBySideChanged = false;
|
||||
if (typeof newOptions.renderSideBySide !== 'undefined') {
|
||||
|
@ -1108,6 +1100,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
|||
|
||||
private _adjustOptionsForSubEditor(options: editorBrowser.IDiffEditorConstructionOptions): editorBrowser.IDiffEditorConstructionOptions {
|
||||
const clonedOptions: editorBrowser.IDiffEditorConstructionOptions = objects.deepClone(options || {});
|
||||
clonedOptions.inDiffEditor = true;
|
||||
clonedOptions.automaticLayout = false;
|
||||
clonedOptions.scrollbar = clonedOptions.scrollbar || {};
|
||||
clonedOptions.scrollbar.vertical = 'visible';
|
||||
|
@ -1125,17 +1118,11 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
|||
|
||||
private _adjustOptionsForLeftHandSide(options: editorBrowser.IDiffEditorConstructionOptions): editorBrowser.IEditorConstructionOptions {
|
||||
const result = this._adjustOptionsForSubEditor(options);
|
||||
result.inDiffEditor = (this._renderSideBySide ? InDiffEditorState.SideBySideLeft : InDiffEditorState.InlineLeft);
|
||||
if (!this._renderSideBySide) {
|
||||
// do not wrap hidden editor
|
||||
result.wordWrap = 'off';
|
||||
result.wordWrapMinified = false;
|
||||
} else if (this._diffWordWrap === 'inherit') {
|
||||
result.wordWrap = this._wordWrap;
|
||||
result.wordWrapMinified = this._wordWrapMinified;
|
||||
// never wrap hidden editor
|
||||
result.wordWrapOverride1 = 'off';
|
||||
} else {
|
||||
result.wordWrap = this._diffWordWrap;
|
||||
result.wordWrapMinified = this._wordWrapMinified;
|
||||
result.wordWrapOverride1 = this._diffWordWrap;
|
||||
}
|
||||
result.readOnly = !this._originalIsEditable;
|
||||
result.extraEditorClassName = 'original-in-monaco-diff-editor';
|
||||
|
@ -1144,12 +1131,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
|||
|
||||
private _adjustOptionsForRightHandSide(options: editorBrowser.IDiffEditorConstructionOptions): editorBrowser.IEditorConstructionOptions {
|
||||
const result = this._adjustOptionsForSubEditor(options);
|
||||
result.inDiffEditor = (this._renderSideBySide ? InDiffEditorState.SideBySideRight : InDiffEditorState.InlineRight);
|
||||
if (this._diffWordWrap === 'inherit') {
|
||||
result.wordWrap = this._wordWrap;
|
||||
} else {
|
||||
result.wordWrap = this._diffWordWrap;
|
||||
}
|
||||
result.wordWrapOverride1 = this._diffWordWrap;
|
||||
result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
|
||||
result.scrollbar!.verticalHasArrows = false;
|
||||
result.extraEditorClassName = 'modified-in-monaco-diff-editor';
|
||||
|
|
|
@ -41,14 +41,6 @@ export const enum EditorAutoIndentStrategy {
|
|||
Full = 4
|
||||
}
|
||||
|
||||
export const enum InDiffEditorState {
|
||||
None = 0,
|
||||
SideBySideLeft = 1,
|
||||
SideBySideRight = 2,
|
||||
InlineLeft = 3,
|
||||
InlineRight = 4
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options for the editor.
|
||||
*/
|
||||
|
@ -56,7 +48,7 @@ export interface IEditorOptions {
|
|||
/**
|
||||
* This editor is used inside a diff editor.
|
||||
*/
|
||||
inDiffEditor?: InDiffEditorState;
|
||||
inDiffEditor?: boolean;
|
||||
/**
|
||||
* The aria label for the editor's textarea (when it is focused).
|
||||
*/
|
||||
|
@ -272,6 +264,14 @@ export interface IEditorOptions {
|
|||
* Defaults to "off".
|
||||
*/
|
||||
wordWrap?: 'off' | 'on' | 'wordWrapColumn' | 'bounded';
|
||||
/**
|
||||
* Override the `wordWrap` setting.
|
||||
*/
|
||||
wordWrapOverride1?: 'off' | 'on' | 'inherit';
|
||||
/**
|
||||
* Override the `wordWrapOverride1` setting.
|
||||
*/
|
||||
wordWrapOverride2?: 'off' | 'on' | 'inherit';
|
||||
/**
|
||||
* Control the wrapping of the editor.
|
||||
* When `wordWrap` = "off", the lines will never wrap.
|
||||
|
@ -281,11 +281,6 @@ export interface IEditorOptions {
|
|||
* Defaults to 80.
|
||||
*/
|
||||
wordWrapColumn?: number;
|
||||
/**
|
||||
* Force word wrapping when the text appears to be of a minified/generated file.
|
||||
* Defaults to true.
|
||||
*/
|
||||
wordWrapMinified?: boolean;
|
||||
/**
|
||||
* Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'.
|
||||
* Defaults to 'same' in vscode and to 'none' in monaco-editor.
|
||||
|
@ -1967,8 +1962,8 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||
EditorOption.glyphMargin, EditorOption.lineDecorationsWidth, EditorOption.folding,
|
||||
EditorOption.minimap, EditorOption.scrollbar, EditorOption.lineNumbers,
|
||||
EditorOption.lineNumbersMinChars, EditorOption.scrollBeyondLastLine,
|
||||
EditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapMinified,
|
||||
EditorOption.accessibilitySupport, EditorOption.inDiffEditor
|
||||
EditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapOverride1, EditorOption.wordWrapOverride2,
|
||||
EditorOption.accessibilitySupport
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -2178,11 +2173,12 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||
const pixelRatio = env.pixelRatio;
|
||||
const viewLineCount = env.viewLineCount;
|
||||
|
||||
const wordWrap = options.get(EditorOption.wordWrap);
|
||||
const wordWrapOverride2 = options.get(EditorOption.wordWrapOverride2);
|
||||
const wordWrapOverride1 = (wordWrapOverride2 === 'inherit' ? options.get(EditorOption.wordWrapOverride1) : wordWrapOverride2);
|
||||
const wordWrap = (wordWrapOverride1 === 'inherit' ? options.get(EditorOption.wordWrap) : wordWrapOverride1);
|
||||
|
||||
const wordWrapColumn = options.get(EditorOption.wordWrapColumn);
|
||||
const wordWrapMinified = options.get(EditorOption.wordWrapMinified);
|
||||
const accessibilitySupport = options.get(EditorOption.accessibilitySupport);
|
||||
const inDiffEditor = options.get(EditorOption.inDiffEditor);
|
||||
const isDominatedByLongLines = env.isDominatedByLongLines;
|
||||
|
||||
const showGlyphMargin = options.get(EditorOption.glyphMargin);
|
||||
|
@ -2233,15 +2229,12 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||
let isViewportWrapping = false;
|
||||
let wrappingColumn = -1;
|
||||
|
||||
if (accessibilitySupport !== AccessibilitySupport.Enabled && inDiffEditor !== InDiffEditorState.InlineLeft) {
|
||||
if (accessibilitySupport !== AccessibilitySupport.Enabled) {
|
||||
// See https://github.com/microsoft/vscode/issues/27766
|
||||
// Never enable wrapping when a screen reader is attached
|
||||
// because arrow down etc. will not move the cursor in the way
|
||||
// a screen reader expects.
|
||||
|
||||
// Also see https://github.com/microsoft/vscode/issues/110897
|
||||
// Never enable wrapping for the left hand side editor of an inline diff editor.
|
||||
if (wordWrapMinified && isDominatedByLongLines) {
|
||||
if (wordWrapOverride1 === 'inherit' && isDominatedByLongLines) {
|
||||
// Force viewport width wrapping if model is dominated by long lines
|
||||
isWordWrapMinified = true;
|
||||
isViewportWrapping = true;
|
||||
|
@ -3756,7 +3749,8 @@ export const enum EditorOption {
|
|||
wordWrapBreakAfterCharacters,
|
||||
wordWrapBreakBeforeCharacters,
|
||||
wordWrapColumn,
|
||||
wordWrapMinified,
|
||||
wordWrapOverride1,
|
||||
wordWrapOverride2,
|
||||
wrappingIndent,
|
||||
wrappingStrategy,
|
||||
showDeprecated,
|
||||
|
@ -4034,8 +4028,8 @@ export const EditorOptions = {
|
|||
{ description: nls.localize('highlightActiveIndentGuide', "Controls whether the editor should highlight the active indent guide.") }
|
||||
)),
|
||||
hover: register(new EditorHover()),
|
||||
inDiffEditor: register(new EditorIntOption(
|
||||
EditorOption.inDiffEditor, 'inDiffEditor', 0, 0, 4
|
||||
inDiffEditor: register(new EditorBooleanOption(
|
||||
EditorOption.inDiffEditor, 'inDiffEditor', false
|
||||
)),
|
||||
letterSpacing: register(new EditorFloatOption(
|
||||
EditorOption.letterSpacing, 'letterSpacing',
|
||||
|
@ -4405,8 +4399,15 @@ export const EditorOptions = {
|
|||
}, "Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.")
|
||||
}
|
||||
)),
|
||||
wordWrapMinified: register(new EditorBooleanOption(
|
||||
EditorOption.wordWrapMinified, 'wordWrapMinified', true,
|
||||
wordWrapOverride1: register(new EditorStringEnumOption(
|
||||
EditorOption.wordWrapOverride1, 'wordWrapOverride1',
|
||||
'inherit' as 'off' | 'on' | 'inherit',
|
||||
['off', 'on', 'inherit'] as const
|
||||
)),
|
||||
wordWrapOverride2: register(new EditorStringEnumOption(
|
||||
EditorOption.wordWrapOverride2, 'wordWrapOverride2',
|
||||
'inherit' as 'off' | 'on' | 'inherit',
|
||||
['off', 'on', 'inherit'] as const
|
||||
)),
|
||||
wrappingIndent: register(new EditorEnumOption(
|
||||
EditorOption.wrappingIndent, 'wrappingIndent',
|
||||
|
|
|
@ -412,7 +412,11 @@ export class CursorMoveCommands {
|
|||
const skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection();
|
||||
let newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);
|
||||
|
||||
if (skipWrappingPointStop && noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) {
|
||||
if (skipWrappingPointStop
|
||||
&& noOfColumns === 1
|
||||
&& cursor.viewState.position.column === viewModel.getLineMinColumn(cursor.viewState.position.lineNumber)
|
||||
&& newViewState.position.lineNumber !== cursor.viewState.position.lineNumber
|
||||
) {
|
||||
// moved over to the previous view line
|
||||
const newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
|
||||
if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {
|
||||
|
@ -445,7 +449,11 @@ export class CursorMoveCommands {
|
|||
const skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection();
|
||||
let newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);
|
||||
|
||||
if (skipWrappingPointStop && noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) {
|
||||
if (skipWrappingPointStop
|
||||
&& noOfColumns === 1
|
||||
&& cursor.viewState.position.column === viewModel.getLineMaxColumn(cursor.viewState.position.lineNumber)
|
||||
&& newViewState.position.lineNumber !== cursor.viewState.position.lineNumber
|
||||
) {
|
||||
// moved over to the next view line
|
||||
const newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
|
||||
if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue