Merge remote-tracking branch 'origin/master' into tyriar/replace_vscode_xterm

This commit is contained in:
Daniel Imms 2019-06-03 13:43:03 -07:00
commit 7dab6dffcc
68 changed files with 1052 additions and 547 deletions

View file

@ -65,7 +65,7 @@ This project incorporates components from the projects listed below. The origina
58. TypeScript-TmLanguage version 1.0.0 (https://github.com/Microsoft/TypeScript-TmLanguage)
59. Unicode version 12.0.0 (http://www.unicode.org/)
60. vscode-logfile-highlighter version 2.4.1 (https://github.com/emilast/vscode-logfile-highlighter)
61. vscode-octicons-font version 1.2.0 (https://github.com/Microsoft/vscode-octicons-font)
61. vscode-octicons-font version 1.3.0 (https://github.com/Microsoft/vscode-octicons-font)
62. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift)
63. Web Background Synchronization (https://github.com/WICG/BackgroundSync)

View file

@ -1,20 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as cp from 'child_process';
import * as path from 'path';
function yarnInstall(packageName: string): void {
cp.execSync(`yarn add --no-lockfile ${packageName}`);
cp.execSync(`yarn add --no-lockfile ${packageName}`, { cwd: path.join( process.cwd(), 'remote') });
}
const product = require('../../../product.json');
const dependencies = product.dependencies || {} as { [name: string]: string; };
Object.keys(dependencies).forEach(name => {
const url = dependencies[name];
yarnInstall(url);
});

View file

@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as cp from 'child_process';
import * as path from 'path';
import * as fs from 'fs';
function yarnInstall(packageName: string, cwd: string): void {
console.log(`yarn add --no-lockfile ${packageName}`, cwd);
cp.execSync(`yarn add --no-lockfile ${packageName}`, { cwd, stdio: 'inherit' });
}
/**
* Install additional dependencies listed on each quality `package.json` file.
*/
function main() {
const quality = process.env['VSCODE_QUALITY'];
if (!quality) {
throw new Error('Missing VSCODE_QUALITY, can\'t install distro');
}
const rootPath = path.dirname(path.dirname(path.dirname(__dirname)));
const qualityPath = path.join(rootPath, 'quality', quality);
const packagePath = path.join(qualityPath, 'package.json');
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
const dependencies = pkg.dependencies || {} as { [name: string]: string; };
Object.keys(dependencies).forEach(name => {
const url = dependencies[name];
const cwd = process.argv.length < 3 ? process.cwd() : path.join(process.cwd(), process.argv[2]);
yarnInstall(url, cwd);
});
}
main();

View file

@ -34,7 +34,8 @@ steps:
yarn gulp mixin
yarn gulp hygiene
yarn monaco-compile-check
node build/azure-pipelines/common/installDistro.js
node build/azure-pipelines/common/installDistroDependencies.js
node build/azure-pipelines/common/installDistroDependencies.js remote
node build/lib/builtInExtensions.js
displayName: Prepare build

View file

@ -0,0 +1,3 @@
#!/usr/bin/env bash
set -e
echo 'noop'

View file

@ -0,0 +1,3 @@
#!/usr/bin/env bash
set -e
echo 'noop'

View file

@ -0,0 +1,65 @@
steps:
- task: NodeTool@0
inputs:
versionSpec: "10.15.1"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs:
versionSpec: "1.10.1"
- task: AzureKeyVault@1
displayName: 'Azure Key Vault: Get Secrets'
inputs:
azureSubscription: 'vscode-builds-subscription'
KeyVaultName: vscode
- task: Docker@1
displayName: 'Pull image'
inputs:
azureSubscriptionEndpoint: 'vscode-builds-subscription'
azureContainerRegistry: vscodehub.azurecr.io
command: 'Run an image'
imageName: 'vscode-linux-build-agent:armhf'
containerCommand: uname
- script: |
set -e
cat << EOF > ~/.netrc
machine monacotools.visualstudio.com
password $(devops-pat)
machine github.com
login vscode
password $(github-distro-mixin-password)
EOF
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git"
git fetch distro
git merge $(node -p "require('./package.json').distro")
CHILD_CONCURRENCY=1 yarn
yarn gulp mixin
yarn gulp hygiene
yarn monaco-compile-check
./build/azure-pipelines/linux/prebuild-arm.sh
displayName: Prepare build
- script: |
set -e
./build/azure-pipelines/linux/build-arm.sh
displayName: Build
- script: |
set -e
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \
./build/azure-pipelines/linux/publish-arm.sh
displayName: Publish
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: 'Component Detection'
continueOnError: true

View file

@ -38,7 +38,8 @@ steps:
yarn gulp mixin
yarn gulp hygiene
yarn monaco-compile-check
node build/azure-pipelines/common/installDistro.js
node build/azure-pipelines/common/installDistroDependencies.js
node build/azure-pipelines/common/installDistroDependencies.js remote
node build/lib/builtInExtensions.js
displayName: Prepare build

View file

@ -0,0 +1,3 @@
#!/usr/bin/env bash
set -e
echo 'noop'

View file

@ -1,11 +1,11 @@
resources:
containers:
- container: vscode-x64
endpoint: VSCodeHub
image: vscodehub.azurecr.io/vscode-linux-build-agent:x64
- container: vscode-ia32
endpoint: VSCodeHub
- container: vscode-ia32
image: vscodehub.azurecr.io/vscode-linux-build-agent:ia32
endpoint: VSCodeHub
- container: snapcraft
image: snapcore/snapcraft
@ -59,6 +59,15 @@ jobs:
steps:
- template: linux/product-build-linux.yml
- job: LinuxArmhf
condition: eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true')
pool:
vmImage: 'Ubuntu-16.04'
variables:
VSCODE_ARCH: armhf
steps:
- template: linux/product-build-linux-arm.yml
- job: macOS
condition: eq(variables['VSCODE_BUILD_MACOS'], 'true')
pool:
@ -76,6 +85,7 @@ jobs:
- Linux
- LinuxSnap
- Linux32
- LinuxArmhf
- macOS
steps:
- template: sync-mooncake.yml

View file

@ -35,7 +35,8 @@ steps:
exec { yarn gulp mixin }
exec { yarn gulp hygiene }
exec { yarn monaco-compile-check }
exec { node build/azure-pipelines/common/installDistro.js }
exec { node build/azure-pipelines/common/installDistroDependencies.js }
exec { node build/azure-pipelines/common/installDistroDependencies.js remote }
exec { node build/lib/builtInExtensions.js }
displayName: Prepare build

View file

@ -27,7 +27,8 @@ gulp.task('mixin', function () {
fancyLog(ansiColors.blue('[mixin]'), `Mixing in sources:`);
return vfs
.src(`quality/${quality}/**`, { base: `quality/${quality}` })
.pipe(filter(function (f) { return !f.isDirectory(); }))
.pipe(filter(f => !f.isDirectory()))
.pipe(filter(['**', '!**/package.json']))
.pipe(productJsonFilter)
.pipe(buffer())
.pipe(json(o => Object.assign({}, require('../product.json'), o)))

View file

@ -13,4 +13,4 @@ gulp.task('vscode-reh-win32-ia32-min', noop);
gulp.task('vscode-reh-win32-x64-min', noop);
gulp.task('vscode-reh-darwin-min', noop);
gulp.task('vscode-reh-linux-x64-min', noop);
gulp.task('vscode-reh-linux-arm-min', noop);
gulp.task('vscode-reh-linux-armhf-min', noop);

View file

@ -6,7 +6,7 @@
"git": {
"name": "octref/language-css",
"repositoryUrl": "https://github.com/octref/language-css",
"commitHash": "6d3a2d01dd67ef062030f4520dd42a5424330a3b"
"commitHash": "377734aad976be88a425aab5667784f3f71ea7e5"
}
},
"license": "MIT",

View file

@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/octref/language-css/commit/6d3a2d01dd67ef062030f4520dd42a5424330a3b",
"version": "https://github.com/octref/language-css/commit/377734aad976be88a425aab5667784f3f71ea7e5",
"name": "CSS",
"scopeName": "source.css",
"patterns": [
@ -606,8 +606,32 @@
]
},
{
"begin": "(?i)(?=@[\\w-]+(\\s|\\(|{|;|/\\*|$))",
"end": "(?<=}|;)(?!\\G)",
"begin": "(?i)(?=@[\\w-]+[^;]+;s*$)",
"end": "(?<=;)(?!\\G)",
"patterns": [
{
"begin": "(?i)\\G(@)[\\w-]+",
"beginCaptures": {
"0": {
"name": "keyword.control.at-rule.css"
},
"1": {
"name": "punctuation.definition.keyword.css"
}
},
"end": ";",
"endCaptures": {
"0": {
"name": "punctuation.terminator.rule.css"
}
},
"name": "meta.at-rule.header.css"
}
]
},
{
"begin": "(?i)(?=@[\\w-]+(\\s|\\(|{|/\\*|$))",
"end": "(?<=})(?!\\G)",
"patterns": [
{
"begin": "(?i)\\G(@)[\\w-]+",

View file

@ -6,7 +6,7 @@
"git": {
"name": "ionide/ionide-fsgrammar",
"repositoryUrl": "https://github.com/ionide/ionide-fsgrammar",
"commitHash": "b2100c95d7857c5421d111a860fcdd20954a0263"
"commitHash": "b57388e5a0971412c081cf0cea8b50b9c24ea4e8"
}
},
"license": "MIT",

View file

@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/ionide/ionide-fsgrammar/commit/b2100c95d7857c5421d111a860fcdd20954a0263",
"version": "https://github.com/ionide/ionide-fsgrammar/commit/b57388e5a0971412c081cf0cea8b50b9c24ea4e8",
"name": "fsharp",
"scopeName": "source.fsharp",
"patterns": [
@ -335,6 +335,44 @@
}
]
},
"anonymous_record_declaration": {
"begin": "(\\{\\|)",
"end": "(\\|\\})",
"beginCaptures": {
"1": {
"name": "keyword.symbol.fsharp"
}
},
"endCaptures": {
"1": {
"name": "keyword.symbol.fsharp"
}
},
"patterns": [
{
"match": "[[:alpha:]0-9'`^_ ]+(:)",
"captures": {
"1": {
"name": "keyword.symbol.fsharp"
}
}
},
{
"match": "([[:alpha:]0-9'`^_ ]+)",
"captures": {
"1": {
"name": "entity.name.type.fsharp"
}
}
},
{
"include": "#anonymous_record_declaration"
},
{
"include": "#keywords"
}
]
},
"record_signature": {
"patterns": [
{
@ -819,6 +857,9 @@
}
]
},
{
"include": "#anonymous_record_declaration"
},
{
"begin": "({)",
"end": "(})",
@ -982,6 +1023,9 @@
}
}
},
{
"include": "#anonymous_record_declaration"
},
{
"include": "#keywords"
}
@ -1062,6 +1106,9 @@
"name": "entity.name.section.fsharp"
}
}
},
{
"include": "#comments"
}
]
},
@ -1255,6 +1302,9 @@
}
}
},
{
"include": "#anonymous_record_declaration"
},
{
"begin": "(\\?{0,1})([[:alpha:]0-9'`^._ ]+)\\s*(:)(\\s*([?[:alpha:]0-9'`^._ ]+)(<))",
"end": "(>)",

View file

@ -6,7 +6,7 @@
"git": {
"name": "fadeevab/make.tmbundle",
"repositoryUrl": "https://github.com/fadeevab/make.tmbundle",
"commitHash": "bd71f44ea55d61be711bd7676e600a7333cc79ea"
"commitHash": "1b05209b483f81f42270bdda5514590e013e4896"
}
},
"licenseDetail": [

View file

@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/fadeevab/make.tmbundle/commit/bd71f44ea55d61be711bd7676e600a7333cc79ea",
"version": "https://github.com/fadeevab/make.tmbundle/commit/1b05209b483f81f42270bdda5514590e013e4896",
"name": "Makefile",
"scopeName": "source.makefile",
"patterns": [
@ -132,6 +132,9 @@
},
{
"include": "#comment"
},
{
"include": "#directives"
}
]
},

View file

@ -6,7 +6,7 @@
"git": {
"name": "language-rust",
"repositoryUrl": "https://github.com/zargony/atom-language-rust",
"commitHash": "5238d9834953ed7c58d9b5b9bb0c084c3c11ecd6"
"commitHash": "7d59e2ad79fbe5925bd2fd3bd3857bf9f421ff6f"
}
},
"license": "MIT",

View file

@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/zargony/atom-language-rust/commit/5238d9834953ed7c58d9b5b9bb0c084c3c11ecd6",
"version": "https://github.com/zargony/atom-language-rust/commit/7d59e2ad79fbe5925bd2fd3bd3857bf9f421ff6f",
"name": "Rust",
"scopeName": "source.rust",
"patterns": [
@ -160,7 +160,7 @@
{
"comment": "Control keyword",
"name": "keyword.control.rust",
"match": "\\b(break|continue|else|if|in|for|loop|match|return|while)\\b"
"match": "\\b(async|await|break|continue|else|if|in|for|loop|match|return|try|while)\\b"
},
{
"comment": "Keyword",

View file

@ -6,6 +6,25 @@
import * as vscode from 'vscode';
import { ResourceMap } from '../utils/resourceMap';
import { DiagnosticLanguage, allDiagnosticLanguages } from '../utils/languageDescription';
import * as arrays from '../utils/arrays';
function diagnosticsEquals(a: vscode.Diagnostic, b: vscode.Diagnostic): boolean {
if (a === b) {
return true;
}
return a.code === b.code
&& a.message === b.message
&& a.severity === b.severity
&& a.source === b.source
&& a.range.isEqual(b.range)
&& arrays.equals(a.relatedInformation || arrays.empty, b.relatedInformation || arrays.empty, (a, b) => {
return a.message === b.message
&& a.location.range.isEqual(b.location.range)
&& a.location.uri.fsPath === b.location.uri.fsPath;
})
&& arrays.equals(a.tags || arrays.empty, b.tags || arrays.empty);
}
export const enum DiagnosticKind {
Syntax,
@ -31,12 +50,10 @@ class FileDiagnostics {
this.language = language;
}
if (diagnostics.length === 0) {
const existing = this._diagnostics.get(kind);
if (!existing || existing && existing.length === 0) {
// No need to update
return false;
}
const existing = this._diagnostics.get(kind);
if (arrays.equals(existing || arrays.empty, diagnostics, diagnosticsEquals)) {
// No need to update
return false;
}
this._diagnostics.set(kind, diagnostics);

View file

@ -2,20 +2,23 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export function equals<T>(one: ReadonlyArray<T>, other: ReadonlyArray<T>, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
if (one.length !== other.length) {
export const empty = Object.freeze([]);
export function equals<T>(
a: ReadonlyArray<T>,
b: ReadonlyArray<T>,
itemEquals: (a: T, b: T) => boolean = (a, b) => a === b
): boolean {
if (a === b) {
return true;
}
if (a.length !== b.length) {
return false;
}
for (let i = 0, len = one.length; i < len; i++) {
if (!itemEquals(one[i], other[i])) {
return false;
}
}
return true;
return a.every((x, i) => itemEquals(x, b[i]));
}
export function flatten<T>(arr: ReadonlyArray<T>[]): T[] {
return ([] as T[]).concat.apply([], arr);
return Array.prototype.concat.apply([], arr);
}

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.35.0",
"distro": "78b820fcfbca46e0a1387efef3b8216e04100f45",
"version": "1.36.0",
"distro": "15aab9a6b297eb15ea96c450d3b92b0758572cca",
"author": {
"name": "Microsoft Corporation"
},
@ -155,4 +155,4 @@
"windows-mutex": "0.2.1",
"windows-process-tree": "0.2.3"
}
}
}

View file

@ -96,6 +96,16 @@ const _empty = '';
const _slash = '/';
const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
function _isQueryStringScheme(scheme: string) {
switch (scheme.toLowerCase()) {
case 'http':
case 'https':
case 'ftp':
return true;
}
return false;
}
/**
* Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.
* This class is a simple parser which creates the basic component parts
@ -282,14 +292,14 @@ export class URI implements UriComponents {
static parse(value: string, _strict: boolean = false): URI {
const match = _regexp.exec(value);
if (!match) {
return new _URI(_empty, _empty, _empty, _empty, _empty);
return new _URI(_empty, _empty, _empty, _empty, _empty, _strict);
}
return new _URI(
match[2] || _empty,
decodeURIComponent(match[4] || _empty),
decodeURIComponent(match[5] || _empty),
decodeURIComponent(match[7] || _empty),
decodeURIComponent(match[9] || _empty),
decodeURIComponentFast(match[4] || _empty, false, false),
decodeURIComponentFast(match[5] || _empty, true, false),
decodeURIComponentFast(match[7] || _empty, false, _isQueryStringScheme(match[2])),
decodeURIComponentFast(match[9] || _empty, false, false),
_strict
);
}
@ -465,6 +475,84 @@ class _URI extends URI {
}
}
function isHex(value: string, pos: number): boolean {
if (pos >= value.length) {
return false;
}
const code = value.charCodeAt(pos);
return (code >= CharCode.Digit0 && code <= CharCode.Digit9)// 0-9
|| (code >= CharCode.a && code <= CharCode.f) //a-f
|| (code >= CharCode.A && code <= CharCode.F); //A-F
}
function decodeURIComponentFast(uriComponent: string, isPath: boolean, isQueryString: boolean): string {
let res: string | undefined;
let nativeDecodePos = -1;
for (let pos = 0; pos < uriComponent.length; pos++) {
const code = uriComponent.charCodeAt(pos);
// decoding needed
if (code === CharCode.PercentSign && isHex(uriComponent, pos + 1) && isHex(uriComponent, pos + 2)) {
const chA = uriComponent.charCodeAt(pos + 1);
const chB = uriComponent.charCodeAt(pos + 2);
// when in a path -> check and accept %2f and %2F (fwd slash)
// when in a query string -> check and accept %3D, %26, and %3B (equals, ampersand, semi-colon)
if (
(isPath && chA === CharCode.Digit2 && (chB === CharCode.F || chB === CharCode.f))
||
(isQueryString && (
(chA === CharCode.Digit2 && chB === CharCode.Digit6) // %26
||
(chA === CharCode.Digit3 && (chB === CharCode.B || chB === CharCode.b || chB === CharCode.D || chB === CharCode.d)) // %3D, %3D
))
) {
if (nativeDecodePos !== -1) {
res += decodeURIComponent(uriComponent.substring(nativeDecodePos, pos));
nativeDecodePos = -1;
}
if (res !== undefined) {
res += uriComponent.substr(pos, 3);
}
pos += 2;
continue;
}
if (res === undefined) {
res = uriComponent.substring(0, pos);
}
if (nativeDecodePos === -1) {
nativeDecodePos = pos;
}
pos += 2;
} else {
if (nativeDecodePos !== -1) {
res += decodeURIComponent(uriComponent.substring(nativeDecodePos, pos));
nativeDecodePos = -1;
}
if (res !== undefined) {
res += String.fromCharCode(code);
}
}
}
if (nativeDecodePos !== -1) {
res += decodeURIComponent(uriComponent.substr(nativeDecodePos));
}
return res !== undefined ? res : uriComponent;
}
// reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2
const encodeTable: { [ch: number]: string } = {
[CharCode.Colon]: '%3A', // gen-delims
@ -490,7 +578,7 @@ const encodeTable: { [ch: number]: string } = {
[CharCode.Space]: '%20',
};
function encodeURIComponentFast(uriComponent: string, allowSlash: boolean): string {
function encodeURIComponentFast(uriComponent: string, isPath: boolean, isQueryString: boolean): string {
let res: string | undefined = undefined;
let nativeEncodePos = -1;
@ -506,7 +594,8 @@ function encodeURIComponentFast(uriComponent: string, allowSlash: boolean): stri
|| code === CharCode.Period
|| code === CharCode.Underline
|| code === CharCode.Tilde
|| (allowSlash && code === CharCode.Slash)
|| (isPath && code === CharCode.Slash) // path => allow slash AS-IS
|| (isQueryString && (code === CharCode.Equals || code === CharCode.Ampersand || code === CharCode.Semicolon)) // query string => allow &=;
) {
// check if we are delaying native encode
if (nativeEncodePos !== -1) {
@ -518,6 +607,20 @@ function encodeURIComponentFast(uriComponent: string, allowSlash: boolean): stri
res += uriComponent.charAt(pos);
}
} else if (code === CharCode.PercentSign && isHex(uriComponent, pos + 1) && isHex(uriComponent, pos + 2)) {
// at percentage encoded value
// check if we are delaying native encode
if (nativeEncodePos !== -1) {
res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));
nativeEncodePos = -1;
}
// check if we write into a new string (by default we try to return the param)
if (res !== undefined) {
res += uriComponent.substr(pos, 3);
}
pos += 2;
} else {
// encoding needed, we need to allocate a new string
if (res === undefined) {
@ -606,6 +709,7 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string {
let res = '';
let { scheme, authority, path, query, fragment } = uri;
if (scheme) {
res += scheme;
res += ':';
@ -622,22 +726,22 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string {
authority = authority.substr(idx + 1);
idx = userinfo.indexOf(':');
if (idx === -1) {
res += encoder(userinfo, false);
res += encoder(userinfo, false, false);
} else {
// <user>:<pass>@<auth>
res += encoder(userinfo.substr(0, idx), false);
res += encoder(userinfo.substr(0, idx), false, false);
res += ':';
res += encoder(userinfo.substr(idx + 1), false);
res += encoder(userinfo.substr(idx + 1), false, false);
}
res += '@';
}
authority = authority.toLowerCase();
idx = authority.indexOf(':');
if (idx === -1) {
res += encoder(authority, false);
res += encoder(authority, false, false);
} else {
// <auth>:<port>
res += encoder(authority.substr(0, idx), false);
res += encoder(authority.substr(0, idx), false, false);
res += authority.substr(idx);
}
}
@ -655,15 +759,15 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string {
}
}
// encode the rest of the path
res += encoder(path, true);
res += encoder(path, true, false);
}
if (query) {
res += '?';
res += encoder(query, false);
res += encoder(query, false, _isQueryStringScheme(scheme));
}
if (fragment) {
res += '#';
res += !skipEncoding ? encodeURIComponentFast(fragment, false) : fragment;
res += !skipEncoding ? encodeURIComponentFast(fragment, false, false) : fragment;
}
return res;
}

View file

@ -109,10 +109,10 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
try {
this.parseErrors = [];
res = this.options.parse ? this.options.parse(raw, this.parseErrors) : json.parse(raw, this.parseErrors);
return res || this.options.defaultConfig;
} catch (error) {
// Ignore parsing errors
return this.options.defaultConfig;
return this.options.defaultConfig; // Ignore parsing errors
}
}

View file

@ -63,7 +63,7 @@ suite('URI', () => {
assert.equal(URI.from({ scheme: 'http', authority: '', path: 'my/path' }).toString(), 'http:/my/path');
assert.equal(URI.from({ scheme: 'http', authority: '', path: '/my/path' }).toString(), 'http:/my/path');
//http://a-test-site.com/#test=true
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: 'test=true' }).toString(), 'http://a-test-site.com/?test%3Dtrue');
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: 'test=true' }).toString(), 'http://a-test-site.com/?test=true');
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: '', fragment: 'test=true' }).toString(), 'http://a-test-site.com/#test%3Dtrue');
});
@ -102,11 +102,11 @@ suite('URI', () => {
test('with, changes', () => {
assert.equal(URI.parse('before:some/file/path').with({ scheme: 'after' }).toString(), 'after:some/file/path');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', path: '/api/files/test.me', query: 't=1234' }).toString(), 'http:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'http:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'https', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'https:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTP', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTP:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTPS', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTPS:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', path: '/api/files/test.me', query: 't=1234' }).toString(), 'http:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'http:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'https', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'https:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTP', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTP:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTPS', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTPS:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'boo', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'boo:/api/files/test.me?t%3D1234');
});
@ -262,11 +262,11 @@ suite('URI', () => {
value = URI.file('c:\\test with %25\\path');
assert.equal(value.path, '/c:/test with %25/path');
assert.equal(value.toString(), 'file:///c%3A/test%20with%20%2525/path');
assert.equal(value.toString(), 'file:///c%3A/test%20with%20%25/path');
value = URI.file('c:\\test with %25\\c#code');
assert.equal(value.path, '/c:/test with %25/c#code');
assert.equal(value.toString(), 'file:///c%3A/test%20with%20%2525/c%23code');
assert.equal(value.toString(), 'file:///c%3A/test%20with%20%25/c%23code');
value = URI.file('\\\\shares');
assert.equal(value.scheme, 'file');
@ -376,7 +376,7 @@ suite('URI', () => {
let uri = URI.parse('https://go.microsoft.com/fwlink/?LinkId=518008');
assert.equal(uri.query, 'LinkId=518008');
assert.equal(uri.toString(true), 'https://go.microsoft.com/fwlink/?LinkId=518008');
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId%3D518008');
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId=518008');
let uri2 = URI.parse(uri.toString());
assert.equal(uri2.query, 'LinkId=518008');
@ -385,7 +385,7 @@ suite('URI', () => {
uri = URI.parse('https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü');
assert.equal(uri.query, 'LinkId=518008&foö&ké¥=üü');
assert.equal(uri.toString(true), 'https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü');
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId%3D518008%26fo%C3%B6%26k%C3%A9%C2%A5%3D%C3%BC%C3%BC');
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId=518008&fo%C3%B6&k%C3%A9%C2%A5=%C3%BC%C3%BC');
uri2 = URI.parse(uri.toString());
assert.equal(uri2.query, 'LinkId=518008&foö&ké¥=üü');
@ -426,6 +426,57 @@ suite('URI', () => {
assert.equal(uri.toString(true), input);
});
test('Support URL specific encodings (query component) #25852', function () {
let input = 'http://example.com/over/there?name=ferret';
assert.equal(input, URI.parse(input).toString());
input = 'http://example.com/over/there?name=ferret&foo=bar';
assert.equal(input, URI.parse(input).toString());
input = 'attp://example.com/over/there?name=ferret';
assert.equal('attp://example.com/over/there?name%3Dferret', URI.parse(input).toString());
});
test('Uri#parse can break path-component #45515', function () {
let uri: URI;
uri = URI.from({ scheme: 's', authority: 'a', path: '/o%2f' });
assert.equal(uri.toString(), 's://a/o%2f');
uri = URI.from({ scheme: 's', authority: 'a', path: '/o%2fü' });
assert.equal(uri.toString(), 's://a/o%2f%C3%BC');
uri = URI.from({ scheme: 's', authority: 'a', path: '/o%2f%' });
assert.equal(uri.toString(), 's://a/o%2f%25');
uri = URI.file('/test with %25/c#code');
assert.equal(uri.path, '/test with %25/c#code');
assert.equal(uri.toString(), 'file:///test%20with%20%25/c%23code');
uri = URI.from({
scheme: 'http',
authority: 'a',
path: '/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg'
});
assert.equal(uri.path, '/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg');
assert.equal(uri.toString(), 'http://a/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg');
assert.equal(URI.parse(uri.toString()).path, '/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg');
assert.equal(uri.toString(), URI.parse(uri.toString()).toString()); // identity
uri = URI.parse('s://a/p%2ft%c3%bc');
assert.equal(uri.path, '/p%2ftü');
uri = URI.parse('s://a/%c3%bcp%2f-REST');
assert.equal(uri.path, '/üp%2f-REST');
uri = URI.parse('s://a/%c3%bcp%2fd%c3%b6wn');
assert.equal(uri.path, '/üp%2fdöwn');
//https://github.com/microsoft/vscode/issues/25852
uri = URI.parse('http://www.test.com/path/service?authId=CN%3DQ10');
assert.equal(uri.query, 'authId=CN%3DQ10');
assert.equal(uri.toString(), 'http://www.test.com/path/service?authId=CN%3DQ10');
});
test('URI - (de)serialize', function () {
const values = [

View file

@ -1,6 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/platform/update/node/update.config.contribution';

View file

@ -9,7 +9,7 @@ import { WindowsManager } from 'vs/code/electron-main/windows';
import { IWindowsService, OpenContext, ActiveWindowManager, IURIToOpen } from 'vs/platform/windows/common/windows';
import { WindowsChannel } from 'vs/platform/windows/node/windowsIpc';
import { WindowsService } from 'vs/platform/windows/electron-main/windowsService';
import { ILifecycleService, LifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
import { getShellEnvironment } from 'vs/code/node/shellEnv';
import { IUpdateService } from 'vs/platform/update/common/update';
import { UpdateChannel } from 'vs/platform/update/node/updateIpc';
@ -36,12 +36,11 @@ import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
import product from 'vs/platform/product/node/product';
import pkg from 'vs/platform/product/node/package';
import { ProxyAuthHandler } from 'vs/code/electron-main/auth';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { IHistoryMainService } from 'vs/platform/history/common/history';
import { withUndefinedAsNull } from 'vs/base/common/types';
import { KeyboardLayoutMonitor } from 'vs/code/electron-main/keyboard';
import { URI } from 'vs/base/common/uri';
import { WorkspacesChannel } from 'vs/platform/workspaces/node/workspacesIpc';
import { IWorkspacesMainService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
@ -90,12 +89,7 @@ export class CodeApplication extends Disposable {
private static APP_ICON_REFRESH_KEY = 'macOSAppIconRefresh7';
private windowsMainService: IWindowsMainService;
private electronIpcServer: ElectronIPCServer;
private sharedProcess: SharedProcess;
private sharedProcessClient: Promise<Client>;
private windowsMainService: IWindowsMainService | undefined;
constructor(
private readonly mainIpcServer: Server,
@ -109,9 +103,6 @@ export class CodeApplication extends Disposable {
) {
super();
this._register(mainIpcServer);
this._register(configurationService);
this.registerListeners();
}
@ -122,12 +113,12 @@ export class CodeApplication extends Disposable {
process.on('uncaughtException', err => this.onUnexpectedError(err));
process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason));
// Contextmenu via IPC support
registerContextMenuListener();
// Dispose on shutdown
this.lifecycleService.onWillShutdown(() => this.dispose());
// Contextmenu via IPC support
registerContextMenuListener();
app.on('accessibility-support-changed', (event: Event, accessibilitySupportEnabled: boolean) => {
if (this.windowsMainService) {
this.windowsMainService.sendToAll('vscode:accessibilitySupportChanged', accessibilitySupportEnabled);
@ -200,7 +191,7 @@ export class CodeApplication extends Disposable {
event.preventDefault();
// Keep in array because more might come!
macOpenFileURIs.push(getURIToOpenFromPathSync(path));
macOpenFileURIs.push(this.getURIToOpenFromPathSync(path));
// Clear previous handler if any
if (runningTimeout !== null) {
@ -217,6 +208,7 @@ export class CodeApplication extends Disposable {
urisToOpen: macOpenFileURIs,
preferNewWindow: true /* dropping on the dock or opening from finder prefers to open in a new window */
});
macOpenFileURIs = [];
runningTimeout = null;
}
@ -224,7 +216,9 @@ export class CodeApplication extends Disposable {
});
app.on('new-window-for-tab', () => {
this.windowsMainService.openNewWindow(OpenContext.DESKTOP); //macOS native tab "+" button
if (this.windowsMainService) {
this.windowsMainService.openNewWindow(OpenContext.DESKTOP); //macOS native tab "+" button
}
});
ipc.on('vscode:exit', (event: Event, code: number) => {
@ -234,25 +228,26 @@ export class CodeApplication extends Disposable {
this.lifecycleService.kill(code);
});
ipc.on('vscode:fetchShellEnv', (event: Event) => {
ipc.on('vscode:fetchShellEnv', async (event: Event) => {
const webContents = event.sender;
getShellEnvironment(this.logService).then(shellEnv => {
try {
const shellEnv = await getShellEnvironment(this.logService);
if (!webContents.isDestroyed()) {
webContents.send('vscode:acceptShellEnv', shellEnv);
}
}, err => {
} catch (error) {
if (!webContents.isDestroyed()) {
webContents.send('vscode:acceptShellEnv', {});
}
this.logService.error('Error fetching shell env', err);
});
this.logService.error('Error fetching shell env', error);
}
});
ipc.on('vscode:extensionHostDebug', (_: Event, windowId: number, broadcast: any) => {
if (this.windowsMainService) {
// Send to all windows (except sender window)
this.windowsMainService.sendToAll('vscode:extensionHostDebug', broadcast, [windowId]);
this.windowsMainService.sendToAll('vscode:extensionHostDebug', broadcast, [windowId]); // Send to all windows (except sender window)
}
});
@ -261,11 +256,28 @@ export class CodeApplication extends Disposable {
ipc.on('vscode:reloadWindow', (event: Event) => event.sender.reload());
powerMonitor.on('resume', () => { // After waking up from sleep
if (this.windowsMainService) {
this.windowsMainService.sendToAll('vscode:osResume', undefined);
}
});
// After waking up from sleep (after window opened)
(async () => {
await this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen);
powerMonitor.on('resume', () => {
if (this.windowsMainService) {
this.windowsMainService.sendToAll('vscode:osResume', undefined);
}
});
})();
// Keyboard layout changes (after window opened)
(async () => {
await this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen);
const nativeKeymap = await import('native-keymap');
nativeKeymap.onDidChangeKeyboardLayout(() => {
if (this.windowsMainService) {
this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false);
}
});
})();
}
private onUnexpectedError(err: Error): void {
@ -317,24 +329,31 @@ export class CodeApplication extends Disposable {
}
// Create Electron IPC Server
this.electronIpcServer = new ElectronIPCServer();
const electronIpcServer = new ElectronIPCServer();
// Resolve unique machine ID
this.logService.trace('Resolving machine identifier...');
const machineId = await this.resolveMachineId();
this.logService.trace(`Resolved machine identifier: ${machineId}`);
// Spawn shared process
this.sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);
this.sharedProcessClient = this.sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main'));
// Spawn shared process after the first window has opened and 3s have passed
const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);
const sharedProcessClient = sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main'));
this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => {
this._register(new RunOnceScheduler(async () => {
const userEnv = await getShellEnvironment(this.logService);
sharedProcess.spawn(userEnv);
}, 3000)).schedule();
});
// Services
const appInstantiationService = await this.initServices(machineId);
const appInstantiationService = await this.createServices(machineId, sharedProcess, sharedProcessClient);
// Create driver
if (this.environmentService.driverHandle) {
(async () => {
const server = await serveDriver(this.electronIpcServer, this.environmentService.driverHandle!, this.environmentService, appInstantiationService);
const server = await serveDriver(electronIpcServer, this.environmentService.driverHandle!, this.environmentService, appInstantiationService);
this.logService.info('Driver started at:', this.environmentService.driverHandle);
this._register(server);
@ -346,10 +365,10 @@ export class CodeApplication extends Disposable {
this._register(authHandler);
// Open Windows
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor));
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));
// Post Open Windows Tasks
appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor));
this.afterWindowOpen();
// Tracing: Stop tracing after windows are ready if enabled
if (this.environmentService.args.trace) {
@ -371,6 +390,63 @@ export class CodeApplication extends Disposable {
return machineId;
}
private async createServices(machineId: string, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> {
const services = new ServiceCollection();
switch (process.platform) {
case 'win32':
services.set(IUpdateService, new SyncDescriptor(Win32UpdateService));
break;
case 'linux':
if (process.env.SNAP && process.env.SNAP_REVISION) {
services.set(IUpdateService, new SyncDescriptor(SnapUpdateService, [process.env.SNAP, process.env.SNAP_REVISION]));
} else {
services.set(IUpdateService, new SyncDescriptor(LinuxUpdateService));
}
break;
case 'darwin':
services.set(IUpdateService, new SyncDescriptor(DarwinUpdateService));
break;
}
services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv]));
services.set(IWindowsService, new SyncDescriptor(WindowsService, [sharedProcess]));
services.set(ILaunchService, new SyncDescriptor(LaunchService));
services.set(IIssueService, new SyncDescriptor(IssueService, [machineId, this.userEnv]));
services.set(IMenubarService, new SyncDescriptor(MenubarService));
const storageMainService = new StorageMainService(this.logService, this.environmentService);
services.set(IStorageMainService, storageMainService);
this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close()));
const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService);
services.set(IBackupMainService, backupMainService);
services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService));
services.set(IURLService, new SyncDescriptor(URLService));
services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService));
// Telemetry
if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
const channel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('telemetryAppender')));
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService));
const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath);
const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath];
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths };
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
} else {
services.set(ITelemetryService, NullTelemetryService);
}
// Init services that require it
await backupMainService.initialize();
return this.instantiationService.createChild(services);
}
private stopTracingEventually(windows: ICodeWindow[]): void {
this.logService.info(`Tracing: waiting for windows to get ready...`);
@ -384,12 +460,14 @@ export class CodeApplication extends Disposable {
contentTracing.stopRecording(join(homedir(), `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`), path => {
if (!timeout) {
this.windowsMainService.showMessageBox({
type: 'info',
message: localize('trace.message', "Successfully created trace."),
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
buttons: [localize('trace.ok', "Ok")]
}, this.windowsMainService.getLastActiveWindow());
if (this.windowsMainService) {
this.windowsMainService.showMessageBox({
type: 'info',
message: localize('trace.message', "Successfully created trace."),
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
buttons: [localize('trace.ok', "Ok")]
}, this.windowsMainService.getLastActiveWindow());
}
} else {
this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`);
}
@ -406,73 +484,7 @@ export class CodeApplication extends Disposable {
});
}
private async initServices(machineId: string): Promise<IInstantiationService> {
const services = new ServiceCollection();
if (process.platform === 'win32') {
services.set(IUpdateService, new SyncDescriptor(Win32UpdateService));
} else if (process.platform === 'linux') {
if (process.env.SNAP && process.env.SNAP_REVISION) {
services.set(IUpdateService, new SyncDescriptor(SnapUpdateService, [process.env.SNAP, process.env.SNAP_REVISION]));
} else {
services.set(IUpdateService, new SyncDescriptor(LinuxUpdateService));
}
} else if (process.platform === 'darwin') {
services.set(IUpdateService, new SyncDescriptor(DarwinUpdateService));
}
services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId]));
services.set(IWindowsService, new SyncDescriptor(WindowsService, [this.sharedProcess]));
services.set(ILaunchService, new SyncDescriptor(LaunchService));
services.set(IIssueService, new SyncDescriptor(IssueService, [machineId, this.userEnv]));
services.set(IMenubarService, new SyncDescriptor(MenubarService));
services.set(IStorageMainService, new SyncDescriptor(StorageMainService));
services.set(IBackupMainService, new SyncDescriptor(BackupMainService));
services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService));
services.set(IURLService, new SyncDescriptor(URLService));
services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService));
// Telemetry
if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
const channel = getDelayedChannel(this.sharedProcessClient.then(c => c.getChannel('telemetryAppender')));
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService));
const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath);
const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath];
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths };
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
} else {
services.set(ITelemetryService, NullTelemetryService);
}
const appInstantiationService = this.instantiationService.createChild(services);
// Init services that require it
await appInstantiationService.invokeFunction(accessor => Promise.all([
this.initStorageService(accessor),
this.initBackupService(accessor)
]));
return appInstantiationService;
}
private initStorageService(accessor: ServicesAccessor): Promise<void> {
const storageMainService = accessor.get(IStorageMainService) as StorageMainService;
// Ensure to close storage on shutdown
this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close()));
return Promise.resolve();
}
private initBackupService(accessor: ServicesAccessor): Promise<void> {
const backupMainService = accessor.get(IBackupMainService) as BackupMainService;
return backupMainService.initialize();
}
private openFirstWindow(accessor: ServicesAccessor): ICodeWindow[] {
const appInstantiationService = accessor.get(IInstantiationService);
private openFirstWindow(accessor: ServicesAccessor, electronIpcServer: ElectronIPCServer, sharedProcessClient: Promise<Client<string>>): ICodeWindow[] {
// Register more Main IPC services
const launchService = accessor.get(ILaunchService);
@ -482,40 +494,40 @@ export class CodeApplication extends Disposable {
// Register more Electron IPC services
const updateService = accessor.get(IUpdateService);
const updateChannel = new UpdateChannel(updateService);
this.electronIpcServer.registerChannel('update', updateChannel);
electronIpcServer.registerChannel('update', updateChannel);
const issueService = accessor.get(IIssueService);
const issueChannel = new IssueChannel(issueService);
this.electronIpcServer.registerChannel('issue', issueChannel);
electronIpcServer.registerChannel('issue', issueChannel);
const workspacesService = accessor.get(IWorkspacesMainService);
const workspacesChannel = appInstantiationService.createInstance(WorkspacesChannel, workspacesService);
this.electronIpcServer.registerChannel('workspaces', workspacesChannel);
const workspacesChannel = new WorkspacesChannel(workspacesService);
electronIpcServer.registerChannel('workspaces', workspacesChannel);
const windowsService = accessor.get(IWindowsService);
const windowsChannel = new WindowsChannel(windowsService);
this.electronIpcServer.registerChannel('windows', windowsChannel);
this.sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel));
electronIpcServer.registerChannel('windows', windowsChannel);
sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel));
const menubarService = accessor.get(IMenubarService);
const menubarChannel = new MenubarChannel(menubarService);
this.electronIpcServer.registerChannel('menubar', menubarChannel);
electronIpcServer.registerChannel('menubar', menubarChannel);
const urlService = accessor.get(IURLService);
const urlChannel = new URLServiceChannel(urlService);
this.electronIpcServer.registerChannel('url', urlChannel);
electronIpcServer.registerChannel('url', urlChannel);
const storageMainService = accessor.get(IStorageMainService);
const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService as StorageMainService));
this.electronIpcServer.registerChannel('storage', storageChannel);
electronIpcServer.registerChannel('storage', storageChannel);
// Log level management
const logLevelChannel = new LogLevelSetterChannel(accessor.get(ILogService));
this.electronIpcServer.registerChannel('loglevel', logLevelChannel);
this.sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel));
electronIpcServer.registerChannel('loglevel', logLevelChannel);
sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel));
// Lifecycle
(this.lifecycleService as LifecycleService).ready();
// Signal phase: ready (services set)
this.lifecycleService.phase = LifecycleMainPhase.Ready;
// Propagate to clients
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); // TODO@Joao: unfold this
@ -523,7 +535,7 @@ export class CodeApplication extends Disposable {
// Create a URL handler which forwards to the last active window
const activeWindowManager = new ActiveWindowManager(windowsService);
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
const urlHandlerChannel = this.electronIpcServer.getChannel('urlHandler', activeWindowRouter);
const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', activeWindowRouter);
const multiplexURLHandler = new URLHandlerChannelClient(urlHandlerChannel);
// On Mac, Code can be running without any open windows, so we must create a window to handle urls,
@ -553,11 +565,9 @@ export class CodeApplication extends Disposable {
// Watch Electron URLs and forward them to the UrlService
const args = this.environmentService.args;
const urls = args['open-url'] ? args._urls : [];
const urlListener = new ElectronURLListener(urls || [], urlService, this.windowsMainService);
const urlListener = new ElectronURLListener(urls || [], urlService, windowsMainService);
this._register(urlListener);
this.windowsMainService.ready(this.userEnv);
// Open our first window
const macOpenFiles: string[] = (<any>global).macOpenFiles;
const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.DESKTOP;
@ -567,9 +577,9 @@ export class CodeApplication extends Disposable {
const noRecentEntry = args['skip-add-to-recently-opened'] === true;
const waitMarkerFileURI = args.wait && args.waitMarkerFilePath ? URI.file(args.waitMarkerFilePath) : undefined;
// new window if "-n" was used without paths
if (args['new-window'] && !hasCliArgs && !hasFolderURIs && !hasFileURIs) {
// new window if "-n" was used without paths
return this.windowsMainService.open({
return windowsMainService.open({
context,
cli: args,
forceNewWindow: true,
@ -582,10 +592,10 @@ export class CodeApplication extends Disposable {
// mac: open-file event received on startup
if (macOpenFiles && macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) {
return this.windowsMainService.open({
return windowsMainService.open({
context: OpenContext.DOCK,
cli: args,
urisToOpen: macOpenFiles.map(getURIToOpenFromPathSync),
urisToOpen: macOpenFiles.map(file => this.getURIToOpenFromPathSync(file)),
noRecentEntry,
waitMarkerFileURI,
initialStartup: true
@ -593,7 +603,7 @@ export class CodeApplication extends Disposable {
}
// default: read paths from cli
return this.windowsMainService.open({
return windowsMainService.open({
context,
cli: args,
forceNewWindow: args['new-window'] || (!hasCliArgs && args['unity-launch']),
@ -604,62 +614,31 @@ export class CodeApplication extends Disposable {
});
}
private afterWindowOpen(accessor: ServicesAccessor): void {
const windowsMainService = accessor.get(IWindowsMainService);
const historyMainService = accessor.get(IHistoryMainService);
if (isWindows) {
// Setup Windows mutex
try {
const Mutex = (require.__$__nodeRequire('windows-mutex') as any).Mutex;
const windowsMutex = new Mutex(product.win32MutexName);
this._register(toDisposable(() => windowsMutex.release()));
} catch (e) {
if (!this.environmentService.isBuilt) {
windowsMainService.showMessageBox({
title: product.nameLong,
type: 'warning',
message: 'Failed to load windows-mutex!',
detail: e.toString(),
noLink: true
});
}
private getURIToOpenFromPathSync(path: string): IURIToOpen {
try {
const fileStat = statSync(path);
if (fileStat.isDirectory()) {
return { folderUri: URI.file(path) };
}
// Ensure Windows foreground love module
try {
// tslint:disable-next-line:no-unused-expression
require.__$__nodeRequire('windows-foreground-love');
} catch (e) {
if (!this.environmentService.isBuilt) {
windowsMainService.showMessageBox({
title: product.nameLong,
type: 'warning',
message: 'Failed to load windows-foreground-love!',
detail: e.toString(),
noLink: true
});
}
if (hasWorkspaceFileExtension(path)) {
return { workspaceUri: URI.file(path) };
}
} catch (error) {
// ignore errors
}
return { fileUri: URI.file(path) };
}
private afterWindowOpen(): void {
// Signal phase: after window open
this.lifecycleService.phase = LifecycleMainPhase.AfterWindowOpen;
// Remote Authorities
this.handleRemoteAuthorities();
// Keyboard layout changes
KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(() => {
this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false);
});
// Jump List
historyMainService.updateWindowsJumpList();
historyMainService.onRecentlyOpenedChange(() => historyMainService.updateWindowsJumpList());
// Start shared process after a while
const sharedProcessSpawn = this._register(new RunOnceScheduler(() => getShellEnvironment(this.logService).then(userEnv => this.sharedProcess.spawn(userEnv)), 3000));
sharedProcessSpawn.schedule();
// Helps application icon refresh after an update with new icon is installed (macOS)
// TODO@Ben remove after a couple of releases
if (isMacintosh) {
@ -697,8 +676,9 @@ export class CodeApplication extends Disposable {
constructor(authority: string, host: string, port: number) {
this._authority = authority;
const options: IConnectionOptions = {
isBuilt: isBuilt,
isBuilt,
commit: product.commit,
webSocketFactory: nodeWebSocketFactory,
addressProvider: {
@ -707,6 +687,7 @@ export class CodeApplication extends Disposable {
}
}
};
this._connection = connectRemoteAgentManagement(options, authority, `main`);
this._disposeRunner = new RunOnceScheduler(() => this.dispose(), 5000);
}
@ -720,6 +701,7 @@ export class CodeApplication extends Disposable {
async getClient(): Promise<Client<RemoteAgentConnectionContext>> {
this._disposeRunner.schedule();
const connection = await this._connection;
return connection.client;
}
}
@ -727,7 +709,9 @@ export class CodeApplication extends Disposable {
const resolvedAuthorities = new Map<string, ResolvedAuthority>();
ipc.on('vscode:remoteAuthorityResolved', (event: Electron.Event, data: ResolvedAuthority) => {
this.logService.info('Received resolved authority', data.authority);
resolvedAuthorities.set(data.authority, data);
// Make sure to close and remove any existing connections
if (connectionPool.has(data.authority)) {
connectionPool.get(data.authority)!.dispose();
@ -736,15 +720,19 @@ export class CodeApplication extends Disposable {
const resolveAuthority = (authority: string): ResolvedAuthority | null => {
this.logService.info('Resolving authority', authority);
if (authority.indexOf('+') >= 0) {
if (resolvedAuthorities.has(authority)) {
return withUndefinedAsNull(resolvedAuthorities.get(authority));
}
this.logService.info('Didnot find resolved authority for', authority);
return null;
} else {
const [host, strPort] = authority.split(':');
const port = parseInt(strPort, 10);
return { authority, host, port };
}
};
@ -753,6 +741,7 @@ export class CodeApplication extends Disposable {
if (request.method !== 'GET') {
return callback(undefined);
}
const uri = URI.parse(request.url);
let activeConnection: ActiveConnection | undefined;
@ -764,9 +753,11 @@ export class CodeApplication extends Disposable {
callback(undefined);
return;
}
activeConnection = new ActiveConnection(uri.authority, resolvedAuthority.host, resolvedAuthority.port);
connectionPool.set(uri.authority, activeConnection);
}
try {
const rawClient = await activeConnection!.getClient();
if (connectionPool.has(uri.authority)) { // not disposed in the meantime
@ -785,16 +776,3 @@ export class CodeApplication extends Disposable {
});
}
}
function getURIToOpenFromPathSync(path: string): IURIToOpen {
try {
const fileStat = statSync(path);
if (fileStat.isDirectory()) {
return { folderUri: URI.file(path) };
} else if (hasWorkspaceFileExtension(path)) {
return { workspaceUri: URI.file(path) };
}
} catch (error) {
}
return { fileUri: URI.file(path) };
}

View file

@ -1,32 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nativeKeymap from 'native-keymap';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
export class KeyboardLayoutMonitor {
public static readonly INSTANCE = new KeyboardLayoutMonitor();
private readonly _emitter: Emitter<void>;
private _registered: boolean;
private constructor() {
this._emitter = new Emitter<void>();
this._registered = false;
}
public onDidChangeKeyboardLayout(callback: () => void): IDisposable {
if (!this._registered) {
this._registered = true;
nativeKeymap.onDidChangeKeyboardLayout(() => {
this._emitter.fire();
});
}
return this._emitter.event(callback);
}
}

View file

@ -22,10 +22,10 @@ interface PostResult {
class Endpoint {
private constructor(
public readonly url: string
readonly url: string
) { }
public static getFromProduct(): Endpoint | undefined {
static getFromProduct(): Endpoint | undefined {
const logUploaderUrl = product.logUploaderUrl;
return logUploaderUrl ? new Endpoint(logUploaderUrl) : undefined;
}

View file

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/code/code.main';
import 'vs/platform/update/node/update.config.contribution';
import { app, dialog } from 'electron';
import { assign } from 'vs/base/common/objects';
import * as platform from 'vs/base/common/platform';
@ -39,6 +39,7 @@ import { uploadLogs } from 'vs/code/electron-main/logUploader';
import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
import { IThemeMainService, ThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
import { once } from 'vs/base/common/functional';
class ExpectedError extends Error {
readonly isExpected = true;
@ -90,17 +91,14 @@ class CodeMain {
// log file access on Windows (https://github.com/Microsoft/vscode/issues/41218)
const bufferLogService = new BufferLogService();
const instantiationService = this.createServices(args, bufferLogService);
const [instantiationService, instanceEnvironment] = this.createServices(args, bufferLogService);
try {
// Init services
await instantiationService.invokeFunction(async accessor => {
const environmentService = accessor.get(IEnvironmentService);
const stateService = accessor.get(IStateService);
const logService = accessor.get(ILogService);
// Patch `process.env` with the instance's environment
const instanceEnvironment = this.patchEnvironment(environmentService);
// Startup
try {
await this.initServices(environmentService, stateService as StateService);
} catch (error) {
@ -110,9 +108,19 @@ class CodeMain {
throw error;
}
});
// Startup
await instantiationService.invokeFunction(async accessor => {
const environmentService = accessor.get(IEnvironmentService);
const logService = accessor.get(ILogService);
const lifecycleService = accessor.get(ILifecycleService);
const configurationService = accessor.get(IConfigurationService);
const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleService, instantiationService, true);
const mainIpcServer = await this.doStartup(logService, environmentService, instantiationService, true);
bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel());
once(lifecycleService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose());
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();
});
@ -121,16 +129,17 @@ class CodeMain {
}
}
private createServices(args: ParsedArgs, bufferLogService: BufferLogService): IInstantiationService {
private createServices(args: ParsedArgs, bufferLogService: BufferLogService): [IInstantiationService, typeof process.env] {
const services = new ServiceCollection();
const environmentService = new EnvironmentService(args, process.execPath);
const instanceEnvironment = this.patchEnvironment(environmentService); // Patch `process.env` with the instance's environment
services.set(IEnvironmentService, environmentService);
const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]);
process.once('exit', () => logService.dispose());
services.set(IEnvironmentService, environmentService);
services.set(ILogService, logService);
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
services.set(IStateService, new SyncDescriptor(StateService));
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath]));
@ -138,12 +147,12 @@ class CodeMain {
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
services.set(IThemeMainService, new SyncDescriptor(ThemeMainService));
return new InstantiationService(services, true);
return [new InstantiationService(services, true), instanceEnvironment];
}
private initServices(environmentService: IEnvironmentService, stateService: StateService): Promise<unknown> {
// Ensure paths for environment service exist
// Environment service (paths)
const environmentServiceInitialization = Promise.all<void | undefined>([
environmentService.extensionsPath,
environmentService.nodeCachedDataDir,
@ -175,7 +184,7 @@ class CodeMain {
return instanceEnvironment;
}
private async doStartup(logService: ILogService, environmentService: IEnvironmentService, instantiationService: IInstantiationService, retry: boolean): Promise<Server> {
private async doStartup(logService: ILogService, environmentService: IEnvironmentService, lifecycleService: ILifecycleService, instantiationService: IInstantiationService, retry: boolean): Promise<Server> {
// Try to setup a server for running. If that succeeds it means
// we are the first instance to startup. Otherwise it is likely
@ -183,6 +192,7 @@ class CodeMain {
let server: Server;
try {
server = await serve(environmentService.mainIPCHandle);
once(lifecycleService.onWillShutdown)(() => server.dispose());
} catch (error) {
// Handle unexpected errors (the only expected error is EADDRINUSE that
@ -226,10 +236,11 @@ class CodeMain {
fs.unlinkSync(environmentService.mainIPCHandle);
} catch (error) {
logService.warn('Could not delete obsolete instance handle', error);
throw error;
}
return this.doStartup(logService, environmentService, instantiationService, false);
return this.doStartup(logService, environmentService, lifecycleService, instantiationService, false);
}
// Tests from CLI require to be the only instance currently
@ -261,8 +272,8 @@ class CodeMain {
if (environmentService.args.status) {
return instantiationService.invokeFunction(async accessor => {
const diagnostics = await accessor.get(IDiagnosticsService).getDiagnostics(launchClient);
console.log(diagnostics);
throw new ExpectedError();
});
}
@ -300,12 +311,14 @@ class CodeMain {
// Print --status usage info
if (environmentService.args.status) {
logService.warn('Warning: The --status argument can only be used if Code is already running. Please run it again after Code has started.');
throw new ExpectedError('Terminating...');
}
// Log uploader usage info
if (typeof environmentService.args['upload-logs'] !== 'undefined') {
logService.warn('Warning: The --upload-logs argument can only be used if Code is already running. Please run it again after Code has started.');
throw new ExpectedError('Terminating...');
}

View file

@ -203,12 +203,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
return !!this.config.extensionTestsPath;
}
/*
get extensionDevelopmentPaths(): string | string[] | undefined {
return this.config.extensionDevelopmentPath;
}
*/
get config(): IWindowConfiguration {
return this.currentConfig;
}

View file

@ -15,7 +15,7 @@ import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window';
import { hasArgs, asArray } from 'vs/platform/environment/node/argv';
import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron';
import { parseLineAndColumnAware } from 'vs/code/node/paths';
import { ILifecycleService, UnloadReason, LifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
import { ILifecycleService, UnloadReason, LifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, IPathsToWaitFor, IEnterWorkspaceResult, IMessageBoxResult, INewWindowOptions, IURIToOpen, isFileToOpen, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
@ -38,6 +38,7 @@ import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage';
import { getWorkspaceIdentifier } from 'vs/platform/workspaces/electron-main/workspacesMainService';
import { once } from 'vs/base/common/functional';
const enum WindowError {
UNRESPONSIVE = 1,
@ -159,9 +160,7 @@ export class WindowsManager implements IWindowsMainService {
private static readonly windowsStateStorageKey = 'windowsState';
private static WINDOWS: ICodeWindow[] = [];
private initialUserEnv: IProcessEnvironment;
private static readonly WINDOWS: ICodeWindow[] = [];
private readonly windowsState: IWindowsState;
private lastClosedWindowState?: IWindowState;
@ -170,19 +169,20 @@ export class WindowsManager implements IWindowsMainService {
private readonly workspacesManager: WorkspacesManager;
private _onWindowReady = new Emitter<ICodeWindow>();
onWindowReady: CommonEvent<ICodeWindow> = this._onWindowReady.event;
readonly onWindowReady: CommonEvent<ICodeWindow> = this._onWindowReady.event;
private _onWindowClose = new Emitter<number>();
onWindowClose: CommonEvent<number> = this._onWindowClose.event;
readonly onWindowClose: CommonEvent<number> = this._onWindowClose.event;
private _onWindowLoad = new Emitter<number>();
onWindowLoad: CommonEvent<number> = this._onWindowLoad.event;
readonly onWindowLoad: CommonEvent<number> = this._onWindowLoad.event;
private _onWindowsCountChanged = new Emitter<IWindowsCountChangedEvent>();
onWindowsCountChanged: CommonEvent<IWindowsCountChangedEvent> = this._onWindowsCountChanged.event;
readonly onWindowsCountChanged: CommonEvent<IWindowsCountChangedEvent> = this._onWindowsCountChanged.event;
constructor(
private readonly machineId: string,
private readonly initialUserEnv: IProcessEnvironment,
@ILogService private readonly logService: ILogService,
@IStateService private readonly stateService: IStateService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ -203,12 +203,50 @@ export class WindowsManager implements IWindowsMainService {
this.dialogs = new Dialogs(stateService, this);
this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this);
this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.setupNativeHelpers());
}
ready(initialUserEnv: IProcessEnvironment): void {
this.initialUserEnv = initialUserEnv;
private setupNativeHelpers(): void {
if (isWindows) {
this.registerListeners();
// Setup Windows mutex
try {
const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex;
const mutex = new WindowsMutex(product.win32MutexName);
once(this.lifecycleService.onWillShutdown)(() => mutex.release());
} catch (e) {
this.logService.error(e);
if (!this.environmentService.isBuilt) {
this.showMessageBox({
title: product.nameLong,
type: 'warning',
message: 'Failed to load windows-mutex!',
detail: e.toString(),
noLink: true
});
}
}
// Dev only: Ensure Windows foreground love module is present
if (!this.environmentService.isBuilt) {
try {
require.__$__nodeRequire('windows-foreground-love');
} catch (e) {
this.logService.error(e);
this.showMessageBox({
title: product.nameLong,
type: 'warning',
message: 'Failed to load windows-foreground-love!',
detail: e.toString(),
noLink: true
});
}
}
}
}
private registerListeners(): void {
@ -543,6 +581,7 @@ export class WindowsManager implements IWindowsMainService {
// Find suitable window or folder path to open files in
const fileToCheck = fileInputs.filesToOpenOrCreate[0] || fileInputs.filesToDiff[0];
// only look at the windows with correct authority
const windows = WindowsManager.WINDOWS.filter(w => w.remoteAuthority === fileInputs!.remoteAuthority);
@ -639,7 +678,6 @@ export class WindowsManager implements IWindowsMainService {
// Handle folders to open (instructed and to restore)
const allFoldersToOpen = arrays.distinct(foldersToOpen, folder => getComparisonKey(folder.folderUri)); // prevent duplicates
if (allFoldersToOpen.length > 0) {
// Check for existing instances
@ -713,7 +751,9 @@ export class WindowsManager implements IWindowsMainService {
if (fileInputs && !emptyToOpen) {
emptyToOpen++;
}
const remoteAuthority = fileInputs ? fileInputs.remoteAuthority : (openConfig.cli && openConfig.cli.remote || undefined);
for (let i = 0; i < emptyToOpen; i++) {
usedWindows.push(this.openInBrowserWindow({
userEnv: openConfig.userEnv,

View file

@ -57,6 +57,7 @@ export async function main(argv: string[]): Promise<any> {
else if (shouldSpawnCliProcess(args)) {
const cli = await new Promise<IMainCli>((c, e) => require(['vs/code/node/cliProcessMain'], c, e));
await cli.main(args);
return;
}

View file

@ -27,12 +27,18 @@ export class CodeActionContextMenu {
private readonly _onApplyCodeAction: (action: CodeAction) => Promise<any>
) { }
async show(actionsToShow: Promise<CodeActionSet>, at?: { x: number; y: number } | Position): Promise<void> {
public async show(actionsToShow: Promise<CodeActionSet>, at?: { x: number; y: number } | Position): Promise<void> {
const codeActions = await actionsToShow;
if (!codeActions.actions.length) {
this._visible = false;
return;
}
if (!this._editor.getDomNode()) {
// cancel when editor went off-dom
this._visible = false;
return Promise.reject(canceled());
}
this._visible = true;
const actions = codeActions.actions.map(action => this.codeActionToAction(action));
this._contextMenuService.showContextMenu({

View file

@ -32,7 +32,7 @@ suite('Configuration', () => {
assert.deepEqual(target, { 'a': { 'b': 2 } });
});
test('removeFromValueTree: remove a single segemented key', () => {
test('removeFromValueTree: remove a single segmented key', () => {
let target = { 'a': 1 };
removeFromValueTree(target, 'a');
@ -40,7 +40,7 @@ suite('Configuration', () => {
assert.deepEqual(target, {});
});
test('removeFromValueTree: remove a single segemented key when its value is undefined', () => {
test('removeFromValueTree: remove a single segmented key when its value is undefined', () => {
let target = { 'a': undefined };
removeFromValueTree(target, 'a');
@ -48,7 +48,7 @@ suite('Configuration', () => {
assert.deepEqual(target, {});
});
test('removeFromValueTree: remove a multi segemented key when its value is undefined', () => {
test('removeFromValueTree: remove a multi segmented key when its value is undefined', () => {
let target = { 'a': { 'b': 1 } };
removeFromValueTree(target, 'a.b');
@ -56,7 +56,7 @@ suite('Configuration', () => {
assert.deepEqual(target, {});
});
test('removeFromValueTree: remove a multi segemented key when its value is array', () => {
test('removeFromValueTree: remove a multi segmented key when its value is array', () => {
let target = { 'a': { 'b': [1] } };
removeFromValueTree(target, 'a.b');
@ -64,7 +64,7 @@ suite('Configuration', () => {
assert.deepEqual(target, {});
});
test('removeFromValueTree: remove a multi segemented key first segment value is array', () => {
test('removeFromValueTree: remove a multi segmented key first segment value is array', () => {
let target = { 'a': [1] };
removeFromValueTree(target, 'a.0');
@ -80,7 +80,7 @@ suite('Configuration', () => {
assert.deepEqual(target, {});
});
test('removeFromValueTree: remove a multi segemented key when the first node has more values', () => {
test('removeFromValueTree: remove a multi segmented key when the first node has more values', () => {
let target = { 'a': { 'b': { 'c': 1 }, 'd': 1 } };
removeFromValueTree(target, 'a.b.c');
@ -88,7 +88,7 @@ suite('Configuration', () => {
assert.deepEqual(target, { 'a': { 'd': 1 } });
});
test('removeFromValueTree: remove a multi segemented key when in between node has more values', () => {
test('removeFromValueTree: remove a multi segmented key when in between node has more values', () => {
let target = { 'a': { 'b': { 'c': { 'd': 1 }, 'd': 1 } } };
removeFromValueTree(target, 'a.b.c.d');
@ -96,7 +96,7 @@ suite('Configuration', () => {
assert.deepEqual(target, { 'a': { 'b': { 'd': 1 } } });
});
test('removeFromValueTree: remove a multi segemented key when the last but one node has more values', () => {
test('removeFromValueTree: remove a multi segmented key when the last but one node has more values', () => {
let target = { 'a': { 'b': { 'c': 1, 'd': 1 } } };
removeFromValueTree(target, 'a.b.c');

View file

@ -82,7 +82,7 @@ suite('ConfigurationModel', () => {
assert.deepEqual(testObject.keys, ['a.b']);
});
test('removeValue: remove a single segemented key', () => {
test('removeValue: remove a single segmented key', () => {
let testObject = new ConfigurationModel({ 'a': 1 }, ['a']);
testObject.removeValue('a');
@ -91,7 +91,7 @@ suite('ConfigurationModel', () => {
assert.deepEqual(testObject.keys, []);
});
test('removeValue: remove a multi segemented key', () => {
test('removeValue: remove a multi segmented key', () => {
let testObject = new ConfigurationModel({ 'a': { 'b': 1 } }, ['a.b']);
testObject.removeValue('a.b');

View file

@ -36,7 +36,7 @@ export interface IConfirmationResult {
/**
* This will only be defined if the confirmation was created
* with the checkox option defined.
* with the checkbox option defined.
*/
checkboxChecked?: boolean;
}

View file

@ -287,6 +287,7 @@ export function parseDebugPort(debugArg: string | undefined, debugBrkArg: string
const portStr = debugBrkArg || debugArg;
const port = Number(portStr) || (!isBuild ? defaultBuildPort : null);
const brk = port ? Boolean(!!debugBrkArg) : false;
return { port, break: brk, debugId };
}
@ -301,9 +302,9 @@ function parsePathArg(arg: string | undefined, process: NodeJS.Process): string
if (path.normalize(arg) === resolved) {
return resolved;
} else {
return path.resolve(process.env['VSCODE_CWD'] || process.cwd(), arg);
}
return path.resolve(process.env['VSCODE_CWD'] || process.cwd(), arg);
}
export function parseUserDataDir(args: ParsedArgs, process: NodeJS.Process): string {

View file

@ -480,12 +480,12 @@ export class ExtensionManagementService extends Disposable implements IExtension
e => Promise.reject(new ExtensionManagementError(this.joinErrors(e).message, INSTALL_ERROR_DELETING)));
}
private rename(identfier: IExtensionIdentifier, extractPath: string, renamePath: string, retryUntil: number): Promise<void> {
private rename(identifier: IExtensionIdentifier, extractPath: string, renamePath: string, retryUntil: number): Promise<void> {
return pfs.rename(extractPath, renamePath)
.then(undefined, error => {
if (isWindows && error && error.code === 'EPERM' && Date.now() < retryUntil) {
this.logService.info(`Failed renaming ${extractPath} to ${renamePath} with 'EPERM' error. Trying again...`, identfier.id);
return this.rename(identfier, extractPath, renamePath, retryUntil);
this.logService.info(`Failed renaming ${extractPath} to ${renamePath} with 'EPERM' error. Trying again...`, identifier.id);
return this.rename(identifier, extractPath, renamePath, retryUntil);
}
return Promise.reject(new ExtensionManagementError(error.message || nls.localize('renameError', "Unknown error while renaming {0} to {1}", extractPath, renamePath), error.code || INSTALL_ERROR_RENAMING));
});
@ -835,8 +835,8 @@ export class ExtensionManagementService extends Disposable implements IExtension
return pfs.rimraf(extension.location.fsPath).then(() => this.logService.info('Deleted from disk', extension.identifier.id, extension.location.fsPath));
}
private isUninstalled(identfier: ExtensionIdentifierWithVersion): Promise<boolean> {
return this.filterUninstalled(identfier).then(uninstalled => uninstalled.length === 1);
private isUninstalled(identifier: ExtensionIdentifierWithVersion): Promise<boolean> {
return this.filterUninstalled(identifier).then(uninstalled => uninstalled.length === 1);
}
private filterUninstalled(...identifiers: ExtensionIdentifierWithVersion[]): Promise<string[]> {

View file

@ -16,11 +16,11 @@ export class ExtensionsManifestCache extends Disposable {
constructor(
private readonly environmentService: IEnvironmentService,
extensionsManagementServuce: IExtensionManagementService
extensionsManagementService: IExtensionManagementService
) {
super();
this._register(extensionsManagementServuce.onDidInstallExtension(e => this.onDidInstallExtension(e)));
this._register(extensionsManagementServuce.onDidUninstallExtension(e => this.onDidUnInstallExtension(e)));
this._register(extensionsManagementService.onDidInstallExtension(e => this.onDidInstallExtension(e)));
this._register(extensionsManagementService.onDidUninstallExtension(e => this.onDidUnInstallExtension(e)));
}
private onDidInstallExtension(e: DidInstallExtensionEvent): void {

View file

@ -517,7 +517,7 @@ interface IBaseStat {
resource: URI;
/**
* The name which is the last segement
* The name which is the last segment
* of the {{path}}.
*/
name: string;
@ -531,7 +531,7 @@ interface IBaseStat {
size?: number;
/**
* The last modifictaion date represented
* The last modification date represented
* as millis from unix epoch.
*
* The value may or may not be resolved as

View file

@ -22,6 +22,8 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label';
import { toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/history/electron-main/historyStorage';
import { exists } from 'vs/base/node/pfs';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
export class HistoryMainService implements IHistoryMainService {
@ -37,10 +39,10 @@ export class HistoryMainService implements IHistoryMainService {
private static readonly recentlyOpenedStorageKey = 'openedPathsList';
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<IHistoryMainService>;
private _onRecentlyOpenedChange = new Emitter<void>();
onRecentlyOpenedChange: CommonEvent<void> = this._onRecentlyOpenedChange.event;
readonly onRecentlyOpenedChange: CommonEvent<void> = this._onRecentlyOpenedChange.event;
private macOSRecentDocumentsUpdater: ThrottledDelayer<void>;
@ -48,9 +50,21 @@ export class HistoryMainService implements IHistoryMainService {
@IStateService private readonly stateService: IStateService,
@ILogService private readonly logService: ILogService,
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
@IEnvironmentService private readonly environmentService: IEnvironmentService
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ILifecycleService lifecycleService: ILifecycleService
) {
this.macOSRecentDocumentsUpdater = new ThrottledDelayer<void>(800);
lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList());
}
private handleWindowsJumpList(): void {
if (!isWindows) {
return; // only on windows
}
this.updateWindowsJumpList();
this.onRecentlyOpenedChange(() => this.updateWindowsJumpList());
}
addRecentlyOpened(newlyAdded: IRecent[]): void {

View file

@ -8,7 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IURLService } from 'vs/platform/url/common/url';
import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { OpenContext, IWindowSettings } from 'vs/platform/windows/common/windows';
import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { whenDeleted } from 'vs/base/node/pfs';
@ -107,7 +107,7 @@ export class LaunchChannel implements IServerChannel {
export class LaunchChannelClient implements ILaunchService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILaunchService>;
constructor(private channel: IChannel) { }
@ -134,7 +134,7 @@ export class LaunchChannelClient implements ILaunchService {
export class LaunchService implements ILaunchService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILaunchService>;
constructor(
@ILogService private readonly logService: ILogService,

View file

@ -29,7 +29,7 @@ export interface BeforeShutdownEvent {
/**
* The reason why the application will be shutting down.
*/
reason: ShutdownReason;
readonly reason: ShutdownReason;
}
/**
@ -51,7 +51,7 @@ export interface WillShutdownEvent {
/**
* The reason why the application is shutting down.
*/
reason: ShutdownReason;
readonly reason: ShutdownReason;
}
export const enum ShutdownReason {

View file

@ -7,11 +7,12 @@ import { ipcMain as ipc, app } from 'electron';
import { ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/common/state';
import { Event, Emitter } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
import { isMacintosh, isWindows } from 'vs/base/common/platform';
import { Disposable } from 'vs/base/common/lifecycle';
import { Barrier } from 'vs/base/common/async';
export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');
@ -38,42 +39,48 @@ export interface ShutdownEvent {
}
export interface ILifecycleService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILifecycleService>;
/**
* Will be true if the program was restarted (e.g. due to explicit request or update).
*/
wasRestarted: boolean;
readonly wasRestarted: boolean;
/**
* Will be true if the program was requested to quit.
*/
quitRequested: boolean;
readonly quitRequested: boolean;
/**
* A flag indicating in what phase of the lifecycle we currently are.
*/
phase: LifecycleMainPhase;
/**
* An event that fires when the application is about to shutdown before any window is closed.
* The shutdown can still be prevented by any window that vetos this event.
*/
onBeforeShutdown: Event<void>;
readonly onBeforeShutdown: Event<void>;
/**
* An event that fires after the onBeforeShutdown event has been fired and after no window has
* vetoed the shutdown sequence. At this point listeners are ensured that the application will
* quit without veto.
*/
onWillShutdown: Event<ShutdownEvent>;
readonly onWillShutdown: Event<ShutdownEvent>;
/**
* An event that fires before a window closes. This event is fired after any veto has been dealt
* with so that listeners know for sure that the window will close without veto.
*/
onBeforeWindowClose: Event<ICodeWindow>;
readonly onBeforeWindowClose: Event<ICodeWindow>;
/**
* An event that fires before a window is about to unload. Listeners can veto this event to prevent
* the window from unloading.
*/
onBeforeWindowUnload: Event<IWindowUnloadEvent>;
readonly onBeforeWindowUnload: Event<IWindowUnloadEvent>;
/**
* Unload a window for the provided reason. All lifecycle event handlers are triggered.
@ -94,6 +101,32 @@ export interface ILifecycleService {
* Forcefully shutdown the application. No livecycle event handlers are triggered.
*/
kill(code?: number): void;
/**
* Returns a promise that resolves when a certain lifecycle phase
* has started.
*/
when(phase: LifecycleMainPhase): Promise<void>;
}
export const enum LifecycleMainPhase {
/**
* The first phase signals that we are about to startup.
*/
Starting = 1,
/**
* Services are ready and first window is about to open.
*/
Ready = 2,
/**
* This phase signals a point in time after the window has opened
* and is typically the best place to do work that is not required
* for the window to open.
*/
AfterWindowOpen = 3
}
export class LifecycleService extends Disposable implements ILifecycleService {
@ -129,6 +162,11 @@ export class LifecycleService extends Disposable implements ILifecycleService {
private readonly _onBeforeWindowUnload = this._register(new Emitter<IWindowUnloadEvent>());
readonly onBeforeWindowUnload: Event<IWindowUnloadEvent> = this._onBeforeWindowUnload.event;
private _phase: LifecycleMainPhase = LifecycleMainPhase.Starting;
get phase(): LifecycleMainPhase { return this._phase; }
private phaseWhen = new Map<LifecycleMainPhase, Barrier>();
constructor(
@ILogService private readonly logService: ILogService,
@IStateService private readonly stateService: IStateService
@ -136,6 +174,7 @@ export class LifecycleService extends Disposable implements ILifecycleService {
super();
this.handleRestarted();
this.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
}
private handleRestarted(): void {
@ -146,10 +185,6 @@ export class LifecycleService extends Disposable implements ILifecycleService {
}
}
ready(): void {
this.registerListeners();
}
private registerListeners(): void {
// before-quit: an event that is fired if application quit was
@ -238,6 +273,40 @@ export class LifecycleService extends Disposable implements ILifecycleService {
return this.pendingWillShutdownPromise;
}
set phase(value: LifecycleMainPhase) {
if (value < this.phase) {
throw new Error('Lifecycle cannot go backwards');
}
if (this._phase === value) {
return;
}
this.logService.trace(`lifecycle (main): phase changed (value: ${value})`);
this._phase = value;
const barrier = this.phaseWhen.get(this._phase);
if (barrier) {
barrier.open();
this.phaseWhen.delete(this._phase);
}
}
async when(phase: LifecycleMainPhase): Promise<void> {
if (phase <= this._phase) {
return;
}
let barrier = this.phaseWhen.get(phase);
if (!barrier) {
barrier = new Barrier();
this.phaseWhen.set(phase, barrier);
}
await barrier.wait();
}
registerWindow(window: ICodeWindow): void {
// track window count
@ -390,10 +459,6 @@ export class LifecycleService extends Disposable implements ILifecycleService {
});
}
/**
* A promise that completes to indicate if the quit request has been veto'd
* by the user or not.
*/
quit(fromUpdate?: boolean): Promise<boolean /* veto */> {
if (this.pendingQuitPromise) {
return this.pendingQuitPromise;

View file

@ -27,22 +27,17 @@ export class FileStorage {
}
async init(): Promise<void> {
try {
const contents = await readFile(this.dbPath);
try {
this.lastFlushedSerializedDatabase = contents.toString();
this._database = JSON.parse(this.lastFlushedSerializedDatabase);
} catch (error) {
this._database = {};
}
} catch (error) {
if (error.code !== 'ENOENT') {
this.onError(error);
}
this._database = {};
if (this._database) {
return; // return if database was already loaded
}
const database = await this.loadAsync();
if (this._database) {
return; // return if database was already loaded
}
this._database = database;
}
private loadSync(): object {
@ -59,6 +54,20 @@ export class FileStorage {
}
}
private async loadAsync(): Promise<object> {
try {
this.lastFlushedSerializedDatabase = (await readFile(this.dbPath)).toString();
return JSON.parse(this.lastFlushedSerializedDatabase);
} catch (error) {
if (error.code !== 'ENOENT') {
this.onError(error);
}
return {};
}
}
getItem<T>(key: string, defaultValue: T): T;
getItem<T>(key: string, defaultValue?: T): T | undefined;
getItem<T>(key: string, defaultValue?: T): T | undefined {

View file

@ -92,7 +92,6 @@ export interface IWindowsMainService {
readonly onWindowClose: Event<number>;
// methods
ready(initialUserEnv: IProcessEnvironment): void;
reload(win: ICodeWindow, cli?: ParsedArgs): void;
enterWorkspace(win: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | undefined>;
closeWorkspace(win: ICodeWindow): void;

4
src/vs/vscode.d.ts vendored
View file

@ -3515,6 +3515,10 @@ declare module 'vscode' {
*
* The editor will only resolve a completion item once.
*
* *Note* that accepting a completion item will not wait for it to be resolved. Because of that [`insertText`](#CompletionItem.insertText),
* [`additionalTextEdits`](#CompletionItem.additionalTextEdits), and [`command`](#CompletionItem.command) should not
* be changed when resolving an item.
*
* @param item A completion item currently active in the UI.
* @param token A cancellation token.
* @return The resolved completion item or a thenable that resolves to of such. It is OK to return the given

View file

@ -469,6 +469,9 @@ export class MainThreadComments extends Disposable implements MainThreadComments
private _handlers = new Map<number, string>();
private _commentControllers = new Map<number, MainThreadCommentController>();
private _activeCommentThread?: MainThreadCommentThread;
private _input?: modes.CommentInput;
private _openPanelListener: IDisposable | null;
constructor(
@ -483,6 +486,26 @@ export class MainThreadComments extends Disposable implements MainThreadComments
this._disposables = [];
this._activeCommentThreadDisposables = [];
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments);
this._disposables.push(this._commentService.onDidChangeActiveCommentThread(async thread => {
let handle = (thread as MainThreadCommentThread).controllerHandle;
let controller = this._commentControllers.get(handle);
if (!controller) {
return;
}
this._activeCommentThreadDisposables = dispose(this._activeCommentThreadDisposables);
this._activeCommentThread = thread as MainThreadCommentThread;
controller.activeCommentThread = this._activeCommentThread;
this._activeCommentThreadDisposables.push(this._activeCommentThread.onDidChangeInput(input => { // todo, dispose
this._input = input;
this._proxy.$onCommentWidgetInputChange(handle, URI.parse(this._activeCommentThread!.resource), this._activeCommentThread!.range, this._input ? this._input.value : undefined);
}));
await this._proxy.$onCommentWidgetInputChange(controller.handle, URI.parse(this._activeCommentThread!.resource), this._activeCommentThread.range, this._input ? this._input.value : undefined);
}));
}
$registerCommentController(handle: number, id: string, label: string): void {

View file

@ -236,7 +236,7 @@ export function createApiFactory(
};
// namespace: env
const env: typeof vscode.env = Object.freeze<typeof vscode.env>({
const env: typeof vscode.env = {
get machineId() { return initData.telemetryInfo.machineId; },
get sessionId() { return initData.telemetryInfo.sessionId; },
get language() { return initData.environment.appLanguage; },
@ -257,7 +257,11 @@ export function createApiFactory(
openExternal(uri: URI) {
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remoteAuthority });
}
});
};
if (!initData.environment.extensionTestsLocationURI) {
// allow to patch env-function when running tests
Object.freeze(env);
}
// namespace: extensions
const extensions: typeof vscode.extensions = {

View file

@ -619,6 +619,7 @@ export class SimpleCommentService implements ICommentService {
onDidSetAllCommentThreads: Event<IWorkspaceCommentThreadsEvent> = Event.None;
onDidUpdateCommentThreads: Event<ICommentThreadChangedEvent> = Event.None;
onDidChangeActiveCommentingRange: Event<{ range: Range; commentingRangesInfo: CommentingRanges; }> = Event.None;
onDidChangeActiveCommentThread: Event<any> = Event.None;
onDidSetDataProvider: Event<void> = Event.None;
onDidDeleteDataProvider: Event<string> = Event.None;
setDocumentComments: any;
@ -649,6 +650,7 @@ export class SimpleCommentService implements ICommentService {
deleteReaction: any;
getReactionGroup: any;
toggleReaction: any;
setActiveCommentThread: any;
}
registerSingleton(ICommentService, SimpleCommentService, true);
//#endregion

View file

@ -424,12 +424,14 @@ export class CommentNode extends Disposable {
uri: this._commentEditor.getModel()!.uri,
value: this.comment.body.value
};
this.commentService.setActiveCommentThread(commentThread);
this._commentEditorDisposables.push(this._commentEditor.onDidFocusEditorWidget(() => {
commentThread.input = {
uri: this._commentEditor!.getModel()!.uri,
value: this.comment.body.value
};
this.commentService.setActiveCommentThread(commentThread);
}));
this._commentEditorDisposables.push(this._commentEditor.onDidChangeModelContent(e => {
@ -439,6 +441,7 @@ export class CommentNode extends Disposable {
let input = commentThread.input;
input.value = newVal;
commentThread.input = input;
this.commentService.setActiveCommentThread(commentThread);
}
}
}));
@ -486,6 +489,7 @@ export class CommentNode extends Disposable {
uri: this._commentEditor.getModel()!.uri,
value: newBody
};
this.commentService.setActiveCommentThread(commentThread);
let commandId = this.comment.editCommand.id;
let args = this.comment.editCommand.arguments || [];
@ -523,6 +527,7 @@ export class CommentNode extends Disposable {
if (result.confirmed) {
try {
if (this.comment.deleteCommand) {
this.commentService.setActiveCommentThread(this.commentThread);
let commandId = this.comment.deleteCommand.id;
let args = this.comment.deleteCommand.arguments || [];

View file

@ -38,6 +38,7 @@ export interface ICommentService {
readonly onDidSetResourceCommentInfos: Event<IResourceCommentThreadEvent>;
readonly onDidSetAllCommentThreads: Event<IWorkspaceCommentThreadsEvent>;
readonly onDidUpdateCommentThreads: Event<ICommentThreadChangedEvent>;
readonly onDidChangeActiveCommentThread: Event<CommentThread | null>;
readonly onDidChangeActiveCommentingRange: Event<{ range: Range, commentingRangesInfo: CommentingRanges }>;
readonly onDidSetDataProvider: Event<void>;
readonly onDidDeleteDataProvider: Event<string>;
@ -69,6 +70,7 @@ export interface ICommentService {
deleteReaction(owner: string, resource: URI, comment: Comment, reaction: CommentReaction): Promise<void>;
getReactionGroup(owner: string): CommentReaction[] | undefined;
toggleReaction(owner: string, resource: URI, thread: CommentThread2, comment: Comment, reaction: CommentReaction): Promise<void>;
setActiveCommentThread(commentThread: CommentThread | null): void;
}
export class CommentService extends Disposable implements ICommentService {
@ -89,6 +91,9 @@ export class CommentService extends Disposable implements ICommentService {
private readonly _onDidUpdateCommentThreads: Emitter<ICommentThreadChangedEvent> = this._register(new Emitter<ICommentThreadChangedEvent>());
readonly onDidUpdateCommentThreads: Event<ICommentThreadChangedEvent> = this._onDidUpdateCommentThreads.event;
private readonly _onDidChangeActiveCommentThread = this._register(new Emitter<CommentThread | null>());
readonly onDidChangeActiveCommentThread = this._onDidChangeActiveCommentThread.event;
private readonly _onDidChangeActiveCommentingRange: Emitter<{
range: Range, commentingRangesInfo:
CommentingRanges
@ -109,6 +114,10 @@ export class CommentService extends Disposable implements ICommentService {
super();
}
setActiveCommentThread(commentThread: CommentThread | null) {
this._onDidChangeActiveCommentThread.fire(commentThread);
}
setDocumentComments(resource: URI, commentInfos: ICommentInfo[]): void {
this._onDidSetResourceCommentInfos.fire({ resource, commentInfos });
}

View file

@ -211,6 +211,10 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._bodyElement = <HTMLDivElement>dom.$('.body');
container.appendChild(this._bodyElement);
dom.addDisposableListener(this._bodyElement, dom.EventType.FOCUS_IN, e => {
this.commentService.setActiveCommentThread(this._commentThread);
});
}
protected _fillHead(container: HTMLElement): void {
@ -265,6 +269,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
} else {
const deleteCommand = (this._commentThread as modes.CommentThread2).deleteCommand;
if (deleteCommand) {
this.commentService.setActiveCommentThread(this._commentThread);
return this.commandService.executeCommand(deleteCommand.id, ...(deleteCommand.arguments || []));
} else if (this._commentEditor.getValue() === '') {
this.commentService.disposeCommentThread(this._owner, this._commentThread.threadId!);
@ -516,6 +521,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
this.commentService.setActiveCommentThread(this._commentThread);
}));
this._commentThreadDisposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => {
@ -526,6 +532,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
newInput.value = modelContent;
thread.input = newInput;
}
this.commentService.setActiveCommentThread(this._commentThread);
}));
this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeInput(input => {
@ -727,6 +734,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
this.commentService.setActiveCommentThread(this._commentThread);
await this.commandService.executeCommand(acceptInputCommand.id, ...(acceptInputCommand.arguments || []));
}));
@ -751,6 +759,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
this.commentService.setActiveCommentThread(this._commentThread);
await this.commandService.executeCommand(command.id, ...(command.arguments || []));
}));
});
@ -821,6 +830,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
this.commentService.setActiveCommentThread(this._commentThread);
let commandId = commentThread.acceptInputCommand.id;
let args = commentThread.acceptInputCommand.arguments || [];

View file

@ -303,7 +303,7 @@ export class Scope extends ExpressionContainer implements IScope {
indexedVariables?: number,
public range?: IRange
) {
super(stackFrame.thread.session, reference, `scope:${stackFrame.getId()}:${name}:${index}`, namedVariables, indexedVariables);
super(stackFrame.thread.session, reference, `scope:${name}:${index}`, namedVariables, indexedVariables);
}
toString(): string {

View file

@ -26,7 +26,6 @@ export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Sourc
* | | | |
* scheme source.path session id source.reference
*
* the arbitrary_path and the session id are encoded with 'encodeURIComponent'
*
*/
@ -49,7 +48,11 @@ export class Source {
}
if (typeof this.raw.sourceReference === 'number' && this.raw.sourceReference > 0) {
this.uri = uri.parse(`${DEBUG_SCHEME}:${encodeURIComponent(path)}?session=${encodeURIComponent(sessionId)}&ref=${this.raw.sourceReference}`);
this.uri = uri.from({
scheme: DEBUG_SCHEME,
path,
query: `session=${sessionId}&ref=${this.raw.sourceReference}`
});
} else {
if (isUri(path)) { // path looks like a uri
this.uri = uri.parse(path);
@ -60,7 +63,11 @@ export class Source {
} else {
// path is relative: since VS Code cannot deal with this by itself
// create a debug url that will result in a DAP 'source' request when the url is resolved.
this.uri = uri.parse(`${DEBUG_SCHEME}:${encodeURIComponent(path)}?session=${encodeURIComponent(sessionId)}`);
this.uri = uri.from({
scheme: DEBUG_SCHEME,
path,
query: `session=${sessionId}`
});
}
}
}
@ -118,7 +125,7 @@ export class Source {
if (pair.length === 2) {
switch (pair[0]) {
case 'session':
sessionId = decodeURIComponent(pair[1]);
sessionId = pair[1];
break;
case 'ref':
sourceReference = parseInt(pair[1]);

View file

@ -5,14 +5,11 @@
import * as nls from 'vs/nls';
import { Event, Emitter } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { append, $, addDisposableListener } from 'vs/base/browser/dom';
import { IStatusbarRegistry, StatusbarItemDescriptor, Extensions, IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { Registry } from 'vs/platform/registry/common/platform';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWindowsService } from 'vs/platform/windows/common/windows';
@ -22,10 +19,11 @@ import product from 'vs/platform/product/node/product';
import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<IExtensionHostProfileService>;
private readonly _onDidChangeState: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
@ -38,6 +36,9 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
private _profileSession: ProfileSession | null;
private _state: ProfileSessionState;
private profilingStatusBarIndicator: IStatusbarEntryAccessor | undefined;
private profilingStatusBarIndicatorLabelUpdater: IDisposable | undefined;
public get state() { return this._state; }
public get lastProfile() { return this._profile; }
@ -46,12 +47,18 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
@IEditorService private readonly _editorService: IEditorService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IWindowsService private readonly _windowsService: IWindowsService,
@IDialogService private readonly _dialogService: IDialogService
@IDialogService private readonly _dialogService: IDialogService,
@IStatusbarService private readonly _statusbarService: IStatusbarService,
) {
super();
this._profile = null;
this._profileSession = null;
this._setState(ProfileSessionState.None);
CommandsRegistry.registerCommand('workbench.action.extensionHostProfilder.stop', () => {
this.stopProfiling();
this._editorService.openEditor(this._instantiationService.createInstance(RuntimeExtensionsInput), { revealIfOpened: true });
});
}
private _setState(state: ProfileSessionState): void {
@ -61,17 +68,48 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
this._state = state;
if (this._state === ProfileSessionState.Running) {
ProfileExtHostStatusbarItem.instance.show(() => {
this.stopProfiling();
this._editorService.openEditor(this._instantiationService.createInstance(RuntimeExtensionsInput), { revealIfOpened: true });
});
this.updateProfilingStatusBarIndicator(true);
} else if (this._state === ProfileSessionState.Stopping) {
ProfileExtHostStatusbarItem.instance.hide();
this.updateProfilingStatusBarIndicator(false);
}
this._onDidChangeState.fire(undefined);
}
private updateProfilingStatusBarIndicator(visible: boolean): void {
if (this.profilingStatusBarIndicatorLabelUpdater) {
this.profilingStatusBarIndicatorLabelUpdater.dispose();
this.profilingStatusBarIndicatorLabelUpdater = undefined;
}
if (visible) {
const indicator: IStatusbarEntry = {
text: nls.localize('profilingExtensionHost', "$(sync~spin) Profiling Extension Host"),
tooltip: nls.localize('selectAndStartDebug', "Click to stop profiling."),
command: 'workbench.action.extensionHostProfilder.stop'
};
const timeStarted = Date.now();
const handle = setInterval(() => {
if (this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator.update({ ...indicator, text: nls.localize('profilingExtensionHostTime', "$(sync~spin) Profiling Extension Host ({0} sec)", Math.round((new Date().getTime() - timeStarted) / 1000)), });
}
}, 1000);
this.profilingStatusBarIndicatorLabelUpdater = toDisposable(() => clearInterval(handle));
if (!this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator = this._statusbarService.addEntry(indicator, StatusbarAlignment.RIGHT);
} else {
this.profilingStatusBarIndicator.update(indicator);
}
} else {
if (this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator.dispose();
this.profilingStatusBarIndicator = undefined;
}
}
}
public startProfiling(): Promise<any> | null {
if (this._state !== ProfileSessionState.None) {
return null;
@ -134,76 +172,3 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
}
}
export class ProfileExtHostStatusbarItem implements IStatusbarItem {
public static instance: ProfileExtHostStatusbarItem;
private toDispose: IDisposable[];
private statusBarItem: HTMLElement;
private label: HTMLElement;
private timeStarted: number;
private labelUpdater: any;
private clickHandler: (() => void) | null;
constructor() {
ProfileExtHostStatusbarItem.instance = this;
this.toDispose = [];
this.timeStarted = 0;
}
public show(clickHandler: () => void) {
this.clickHandler = clickHandler;
if (this.timeStarted === 0) {
this.timeStarted = new Date().getTime();
this.statusBarItem.hidden = false;
this.labelUpdater = setInterval(() => {
this.updateLabel();
}, 1000);
this.updateLabel();
}
}
public hide() {
this.clickHandler = null;
this.statusBarItem.hidden = true;
this.timeStarted = 0;
clearInterval(this.labelUpdater);
this.labelUpdater = null;
}
public render(container: HTMLElement): IDisposable {
if (!this.statusBarItem && container) {
this.statusBarItem = append(container, $('.profileExtHost-statusbar-item'));
this.toDispose.push(addDisposableListener(this.statusBarItem, 'click', () => {
if (this.clickHandler) {
this.clickHandler();
}
}));
this.statusBarItem.title = nls.localize('selectAndStartDebug', "Click to stop profiling.");
const a = append(this.statusBarItem, $('a'));
append(a, $('.icon'));
this.label = append(a, $('span.label'));
this.updateLabel();
this.statusBarItem.hidden = true;
}
return this;
}
private updateLabel() {
let label = 'Profiling Extension Host';
if (this.timeStarted > 0) {
let secondsRecoreded = (new Date().getTime() - this.timeStarted) / 1000;
label = `Profiling Extension Host (${Math.round(secondsRecoreded)} sec)`;
}
this.label.textContent = label;
}
public dispose(): void {
this.toDispose = dispose(this.toDispose);
}
}
Registry.as<IStatusbarRegistry>(Extensions.Statusbar).registerStatusbarItem(
new StatusbarItemDescriptor(ProfileExtHostStatusbarItem, StatusbarAlignment.RIGHT)
);

View file

@ -7,7 +7,7 @@ import { localize } from 'vs/nls';
import { dispose, Disposable } from 'vs/base/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { Event, Emitter } from 'vs/base/common/event';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { isPromiseCanceledError, getErrorMessage } from 'vs/base/common/errors';
import { PagedModel, IPagedModel, IPager, DelayedPagedModel } from 'vs/base/common/paging';
import { SortBy, SortOrder, IQueryOptions, IExtensionTipsService, IExtensionRecommendation, IExtensionManagementServer, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
@ -69,9 +69,13 @@ export interface ExtensionsListViewOptions extends IViewletViewOptions {
server?: IExtensionManagementServer;
}
class ExtensionListViewWarning extends Error { }
export class ExtensionsListView extends ViewletPanel {
private readonly server: IExtensionManagementServer | undefined;
private messageContainer: HTMLElement;
private messageStatus: HTMLElement;
private messageBox: HTMLElement;
private extensionsList: HTMLElement;
private badge: CountBadge;
@ -117,7 +121,9 @@ export class ExtensionsListView extends ViewletPanel {
renderBody(container: HTMLElement): void {
this.extensionsList = append(container, $('.extensions-list'));
this.messageBox = append(container, $('.message'));
this.messageContainer = append(container, $('.message-container'));
this.messageStatus = append(this.messageContainer, $(''));
this.messageBox = append(this.messageContainer, $('.message'));
const delegate = new Delegate();
const extensionsViewState = new ExtensionsViewState();
const renderer = this.instantiationService.createInstance(Renderer, extensionsViewState);
@ -178,12 +184,11 @@ export class ExtensionsListView extends ViewletPanel {
};
const errorCallback = (e: Error) => {
const errorCallback = (e: any) => {
const model = new PagedModel([]);
if (!isPromiseCanceledError(e)) {
this.queryRequest = null;
console.warn('Error querying extensions gallery', e);
this.setModel(model, true);
this.setModel(model, e);
}
return this.list ? this.list.model : model;
};
@ -238,7 +243,11 @@ export class ExtensionsListView extends ViewletPanel {
if (ExtensionsListView.isLocalExtensionsQuery(query.value) || /@builtin/.test(query.value)) {
return this.queryLocal(query, options);
}
return this.queryGallery(query, options, token);
return this.queryGallery(query, options, token)
.then(null, e => {
console.warn('Error querying extensions gallery', getErrorMessage(e));
return Promise.reject(new ExtensionListViewWarning(localize('galleryError', "We cannot connect to the Extensions Marketplace at this time, please try again later.")));
});
}
private async queryByIds(ids: string[], options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
@ -696,23 +705,30 @@ export class ExtensionsListView extends ViewletPanel {
});
}
private setModel(model: IPagedModel<IExtension>, isGalleryError?: boolean) {
private setModel(model: IPagedModel<IExtension>, error?: any) {
if (this.list) {
this.list.model = new DelayedPagedModel(model);
this.list.scrollTop = 0;
const count = this.count();
toggleClass(this.extensionsList, 'hidden', count === 0);
toggleClass(this.messageBox, 'hidden', count > 0);
toggleClass(this.messageContainer, 'hidden', count > 0);
this.badge.setCount(count);
if (count === 0 && this.isBodyVisible()) {
this.messageBox.textContent = isGalleryError ? localize('galleryError', "We cannot connect to the Extensions Marketplace at this time, please try again later.") : localize('no extensions found', "No extensions found.");
if (isGalleryError) {
alert(this.messageBox.textContent);
if (error) {
if (error instanceof ExtensionListViewWarning) {
this.messageStatus.className = 'message-status warning';
this.messageBox.textContent = getErrorMessage(error);
} else {
this.messageStatus.className = 'message-status error';
this.messageBox.textContent = localize('error', "Error while loading extensions. {0}", getErrorMessage(error));
}
} else {
this.messageStatus.className = '';
this.messageBox.textContent = localize('no extensions found', "No extensions found.");
}
} else {
this.messageBox.textContent = '';
alert(this.messageBox.textContent);
}
}
}

View file

@ -38,7 +38,7 @@
}
.extensions-viewlet > .extensions .extensions-list.hidden,
.extensions-viewlet > .extensions .message.hidden {
.extensions-viewlet > .extensions .message-container.hidden {
display: none;
visibility: hidden;
}
@ -51,9 +51,35 @@
flex: 1;
}
.extensions-viewlet > .extensions .message {
.extensions-viewlet > .extensions .message-container {
padding: 5px 9px 5px 16px;
cursor: default;
display: flex;
}
.extensions-viewlet > .extensions .message-container .message-status {
height: 16px;
width: 16px;
}
.extensions-viewlet > .extensions .message-container .message-status.warning {
background: url('status-warning.svg') center center no-repeat;
}
.extensions-viewlet > .extensions .message-container .message-status.error {
background: url('status-error.svg') center center no-repeat;
}
.vs-dark .extensions-viewlet > .extensions .message-container .message-status.warning {
background: url('status-warning-inverse.svg') center center no-repeat;
}
.vs-dark .extensions-viewlet > .extensions .message-container .message-status.error {
background: url('status-error-inverse.svg') center center no-repeat;
}
.extensions-viewlet > .extensions .message-container .message {
padding-left: 5px;
}
.extensions-viewlet > .extensions .monaco-list-row > .bookmark {

View file

@ -36,20 +36,3 @@
.runtime-extensions-editor .monaco-action-bar .actions-container {
justify-content: left;
}
.monaco-workbench .part.statusbar .profileExtHost-statusbar-item .icon {
background: url('profile-stop.svg') no-repeat;
display: inline-block;
padding-right: 2px;
padding-bottom: 2px;
width: 16px;
height: 16px;
vertical-align: middle;
animation:fade 1000ms infinite;
}
@keyframes fade {
from { opacity: 1.0; }
50% { opacity: 0.5; }
to { opacity: 1.0; }
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" height="16" width="16"><circle cx="8" cy="8" r="6" fill="#1E1E1E"/><path d="M8 3C5.238 3 3 5.238 3 8s2.238 5 5 5 5-2.238 5-5-2.238-5-5-5zm3 7l-1 1-2-2-2 2-1-1 2-2.027L5 6l1-1 2 2 2-2 1 1-2 1.973L11 10z" fill="#F48771"/><path fill="#252526" d="M11 6l-1-1-2 2-2-2-1 1 2 1.973L5 10l1 1 2-2 2 2 1-1-2-2.027z"/></svg>

After

Width:  |  Height:  |  Size: 372 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle cx="8" cy="8" r="6" fill="#F6F6F6"/><path d="M8 3C5.238 3 3 5.238 3 8s2.238 5 5 5 5-2.238 5-5-2.238-5-5-5zm3 7l-1 1-2-2-2 2-1-1 2-2.027L5 6l1-1 2 2 2-2 1 1-2 1.973L11 10z" fill="#E51400"/><path fill="#fff" d="M11 6l-1-1-2 2-2-2-1 1 2 1.973L5 10l1 1 2-2 2 2 1-1-2-2.027z"/></svg>

After

Width:  |  Height:  |  Size: 403 B

View file

@ -24,6 +24,7 @@ import { URI } from 'vs/base/common/uri';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWindowService } from 'vs/platform/windows/common/windows';
import * as perf from 'vs/base/common/performance';
class PartsSplash {
@ -45,14 +46,20 @@ class PartsSplash {
@IEditorGroupsService editorGroupsService: IEditorGroupsService,
@IConfigurationService configService: IConfigurationService,
) {
lifecycleService.when(LifecyclePhase.Restored).then(_ => this._removePartsSplash());
lifecycleService.when(LifecyclePhase.Restored).then(_ => {
this._removePartsSplash();
perf.mark('didRemovePartsSplash');
});
Event.debounce(Event.any<any>(
onDidChangeFullscreen,
editorGroupsService.onDidLayout
), () => { }, 800)(this._savePartsSplash, this, this._disposables);
configService.onDidChangeConfiguration(e => {
this._didChangeTitleBarStyle = e.affectsConfiguration('window.titleBarStyle');
if (e.affectsConfiguration('window.titleBarStyle')) {
this._didChangeTitleBarStyle = true;
this._savePartsSplash();
}
}, this, this._disposables);
}

View file

@ -15,6 +15,9 @@ yarn smoketest
# Build
yarn smoketest --build PATH_TO_NEW_BUILD_PARENT_FOLDER --stable-build PATH_TO_LAST_STABLE_BUILD_PARENT_FOLDER
# Remote
yarn smoketest --build PATH_TO_NEW_BUILD_PARENT_FOLDER --remote
```
### Run for a release

View file

@ -10,7 +10,7 @@ export class References {
private static readonly REFERENCES_WIDGET = '.monaco-editor .zone-widget .zone-widget-container.peekview-widget.reference-zone-widget.results-loaded';
private static readonly REFERENCES_TITLE_FILE_NAME = `${References.REFERENCES_WIDGET} .head .peekview-title .filename`;
private static readonly REFERENCES_TITLE_COUNT = `${References.REFERENCES_WIDGET} .head .peekview-title .meta`;
private static readonly REFERENCES = `${References.REFERENCES_WIDGET} .body .ref-tree.inline .monaco-list-row .reference`;
private static readonly REFERENCES = `${References.REFERENCES_WIDGET} .body .ref-tree.inline .monaco-list-row .highlight`;
constructor(private code: Code) { }

View file

@ -541,7 +541,6 @@
"**/vs/base/parts/**/{common,browser,node,electron-main}/**",
"**/vs/platform/**/{common,browser,node,electron-main}/**",
"**/vs/code/**/{common,browser,node,electron-main}/**",
"**/vs/code/code.main",
"*" // node modules
]
},