Merge branch 'master' into master

This commit is contained in:
Martin Aeschlimann 2020-12-09 10:40:30 +01:00 committed by GitHub
commit 49dc593a83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
280 changed files with 3644 additions and 2529 deletions

13
.github/commands.json vendored
View file

@ -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",

View file

@ -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')

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -104,7 +104,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS $MILESTONE label:candidate",
"value": "$REPOS $MILESTONE is:open label:candidate",
"editable": true
}
]

View file

@ -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",

View file

@ -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
},
{

View file

@ -1,3 +1,3 @@
disturl "https://electronjs.org/headers"
target "9.3.5"
target "11.0.3"
runtime "electron"

View file

@ -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

View file

@ -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

View file

@ -1 +1 @@
2020-11-30T16:21:34.566Z
2020-12-05T15:02:48.675Z

View file

@ -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(() => {

View file

@ -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(() => {

View file

@ -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(() => {

View 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');
}

View file

@ -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) {

View file

@ -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:

View file

@ -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>

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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);
}

View file

@ -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

View file

@ -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);

View file

@ -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',

View file

@ -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": {

View file

@ -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 [];
}

View file

@ -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;

View file

@ -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);

View file

@ -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) {

View file

@ -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);
}
}
}

View file

@ -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[]> {

View file

@ -144,7 +144,7 @@
"null"
],
"scope": "resource",
"default": "null",
"default": null,
"description": "%html.format.wrapAttributesIndentSize.desc%"
},
"html.format.templating": {

View file

@ -17,6 +17,18 @@
]
],
"autoClosingPairs": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
],
{
"open": "'",
"close": "'",

View file

@ -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;

View file

@ -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}`);
}

View file

@ -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>();

View file

@ -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;

View file

@ -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);
}

View file

@ -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);
}
}
}

View file

@ -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,

View file

@ -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"
}
},
{

View file

@ -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",

View file

@ -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",

View file

@ -1,3 +1,3 @@
disturl "http://nodejs.org/dist"
target "12.14.1"
target "12.18.3"
runtime "node"

View file

@ -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"
}
}

View file

@ -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"

View file

@ -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

View file

@ -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;

View file

@ -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
View file

@ -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() {

View file

@ -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'
}];

View file

@ -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;
}
/**

View file

@ -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)));

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 {

View file

@ -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

View file

@ -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;

View file

@ -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));

View file

@ -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('$', () => {

View file

@ -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
});
});
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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));
}));
});
}

View file

@ -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');

View file

@ -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>

View file

@ -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);
});

View file

@ -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(() => {

View file

@ -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.

View file

@ -69,6 +69,7 @@ export interface IBulkEditOptions {
progress?: IProgress<IProgressStep>;
token?: CancellationToken;
showPreview?: boolean;
suppressPreview?: boolean;
label?: string;
quotableLabel?: string;
undoRedoSource?: UndoRedoSource;

View file

@ -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(),

View file

@ -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;
}

View file

@ -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));
}

View file

@ -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';

View file

@ -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',

View file

@ -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