Merge branch 'master' into sandy081/userDataFileProvider

This commit is contained in:
Sandeep Somavarapu 2019-06-30 21:06:12 +02:00
commit 6ee407f3a7
241 changed files with 3153 additions and 2498 deletions

3
.gitignore vendored
View file

@ -18,6 +18,9 @@ out-vscode-min/
out-vscode-reh/
out-vscode-reh-min/
out-vscode-reh-pkg/
out-vscode-web/
out-vscode-web-min/
out-vscode-web-pkg/
src/vs/server
resources/server
build/node_modules

View file

@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron"
target "4.2.4"
target "4.2.5"
runtime "electron"

View file

@ -146,6 +146,10 @@ async function ensureVersionAndSymbols(options: IOptions) {
// Check version does not exist
console.log(`HockeyApp: checking for existing version ${options.versions.code} (${options.platform})`);
const versions = await getVersions({ accessToken: options.access.hockeyAppToken, appId: options.access.hockeyAppId });
if (!Array.isArray(versions.app_versions)) {
throw new Error(`Unexpected response: ${JSON.stringify(versions)}`);
}
if (versions.app_versions.some(v => v.version === options.versions.code)) {
console.log(`HockeyApp: Returning without uploading symbols because version ${options.versions.code} (${options.platform}) was already found`);
return;
@ -184,6 +188,10 @@ const hockeyAppToken = process.argv[3];
const is64 = process.argv[4] === 'x64';
const hockeyAppId = process.argv[5];
if (process.argv.length !== 6) {
throw new Error(`HockeyApp: Unexpected number of arguments. Got ${process.argv}`);
}
let platform: Platform;
if (process.platform === 'darwin') {
platform = Platform.MAC_OS;
@ -211,7 +219,9 @@ if (repository && codeVersion && electronVersion && (product.quality === 'stable
}).then(() => {
console.log('HockeyApp: done');
}).catch(error => {
console.error(`HockeyApp: error (${error})`);
console.error(`HockeyApp: error ${error} (AppID: ${hockeyAppId})`);
return process.exit(1);
});
} else {
console.log(`HockeyApp: skipping due to unexpected context (repository: ${repository}, codeVersion: ${codeVersion}, electronVersion: ${electronVersion}, quality: ${product.quality})`);

View file

@ -11,9 +11,9 @@ steps:
inputs:
versionSpec: "1.10.1"
- script: |
yarn
yarn --frozen-lockfile
displayName: Install Dependencies
condition: ne(variables['CacheRestored'], 'true')
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'

View file

@ -37,7 +37,7 @@ steps:
- script: |
set -e
yarn
yarn --frozen-lockfile
displayName: Install dependencies
- script: |
@ -59,6 +59,21 @@ steps:
node build/lib/builtInExtensions.js
displayName: Install distro dependencies and extensions
- script: |
set -e
cd $BUILD_STAGINGDIRECTORY
git clone https://github.com/microsoft/vscode-telemetry-extractor.git
cd vscode-telemetry-extractor
git checkout 3b04aba5bfdfcca1a5426cd2c51a90d18740d0bc
npm i
npm run setup-extension-repos
node ./out/cli-extract.js --sourceDir $BUILD_SOURCESDIRECTORY --excludedDirPattern extensions --outputDir . --applyEndpoints --includeIsMeasurement --patchWebsiteEvents
node ./out/cli-extract-extensions.js --sourceDir ./src/telemetry-sources --outputDir . --applyEndpoints --includeIsMeasurement
mkdir -p $BUILD_SOURCESDIRECTORY/.build/telemetry
mv declarations-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-core.json
mv declarations-extensions-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-extensions.json
displayName: Extract Telemetry
- script: |
set -e
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \

View file

@ -19,9 +19,9 @@ steps:
inputs:
versionSpec: "1.10.1"
- script: |
yarn
yarn --frozen-lockfile
displayName: Install Dependencies
condition: ne(variables['CacheRestored'], 'true')
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'

View file

@ -46,7 +46,7 @@ steps:
- script: |
set -e
CHILD_CONCURRENCY=1 yarn
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
displayName: Install dependencies
- script: |

View file

@ -46,7 +46,7 @@ steps:
- script: |
set -e
CHILD_CONCURRENCY=1 yarn
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
displayName: Install dependencies
- script: |

View file

@ -38,7 +38,7 @@ steps:
- script: |
set -e
CHILD_CONCURRENCY=1 yarn
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
displayName: Install dependencies
- script: |
@ -60,6 +60,21 @@ steps:
node build/lib/builtInExtensions.js
displayName: Install distro dependencies and extensions
- script: |
set -e
cd $BUILD_STAGINGDIRECTORY
git clone https://github.com/microsoft/vscode-telemetry-extractor.git
cd vscode-telemetry-extractor
git checkout 3b04aba5bfdfcca1a5426cd2c51a90d18740d0bc
npm i
npm run setup-extension-repos
node ./out/cli-extract.js --sourceDir $BUILD_SOURCESDIRECTORY --excludedDirPattern extensions --outputDir . --applyEndpoints --includeIsMeasurement --patchWebsiteEvents
node ./out/cli-extract-extensions.js --sourceDir ./src/telemetry-sources --outputDir . --applyEndpoints --includeIsMeasurement
mkdir -p $BUILD_SOURCESDIRECTORY/.build/telemetry
mv declarations-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-core.json
mv declarations-extensions-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-extensions.json
displayName: Extract Telemetry
- script: |
set -e
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \

View file

@ -51,7 +51,7 @@ jobs:
- template: linux/snap-build-linux.yml
- job: LinuxArmhf
condition: eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true')
condition: and(eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable'))
timeoutInMinutes: 120
pool:
vmImage: 'Ubuntu-16.04'
@ -61,7 +61,7 @@ jobs:
- template: linux/product-build-linux-arm.yml
- job: LinuxAlpine
condition: eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true')
condition: and(eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable'))
timeoutInMinutes: 120
pool:
vmImage: 'Ubuntu-16.04'

View file

@ -15,9 +15,9 @@ steps:
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
vstsFeed: '$(ArtifactFeed)'
- powershell: |
yarn
yarn --frozen-lockfile
displayName: Install Dependencies
condition: ne(variables['CacheRestored'], 'true')
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'

View file

@ -22,8 +22,6 @@ steps:
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
"machine monacotools.visualstudio.com`npassword $(devops-pat)`nmachine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII
$env:npm_config_arch="$(VSCODE_ARCH)"
$env:CHILD_CONCURRENCY="1"
exec { git config user.email "vscode@microsoft.com" }
exec { git config user.name "VSCode" }
@ -40,7 +38,9 @@ steps:
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { yarn }
$env:npm_config_arch="$(VSCODE_ARCH)"
$env:CHILD_CONCURRENCY="1"
exec { yarn --frozen-lockfile }
displayName: Install dependencies
- powershell: |
@ -65,6 +65,22 @@ steps:
exec { node build/lib/builtInExtensions.js }
displayName: Install distro dependencies and extensions
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
cd $env:BUILD_STAGINGDIRECTORY
git clone https://github.com/microsoft/vscode-telemetry-extractor.git
cd vscode-telemetry-extractor
git checkout 3b04aba5bfdfcca1a5426cd2c51a90d18740d0bc
npm i
npm run setup-extension-repos
node .\out\cli-extract.js --sourceDir $env:BUILD_SOURCESDIRECTORY --excludedDirPattern extensions --outputDir . --applyEndpoints --includeIsMeasurement --patchWebsiteEvents
node .\out\cli-extract-extensions.js --sourceDir .\src\telemetry-sources --outputDir . --applyEndpoints --includeIsMeasurement
mkdir $env:BUILD_SOURCESDIRECTORY\.build\telemetry -ea 0
mv declarations-resolved.json $env:BUILD_SOURCESDIRECTORY\.build\telemetry\telemetry-core.json
mv declarations-extensions-resolved.json $env:BUILD_SOURCESDIRECTORY\.build\telemetry\telemetry-extensions.json
displayName: Extract Telemetry
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
@ -168,6 +184,7 @@ steps:
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)"
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)"
$env:VSCODE_HOCKEYAPP_TOKEN = "$(vscode-hockeyapp-token)"
$env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)"
.\build\azure-pipelines\win32\publish.ps1
displayName: Publish

View file

@ -175,6 +175,17 @@ gulp.task('tslint', () => {
function hygiene(some) {
let errorCount = 0;
const productJson = es.through(function (file) {
const product = JSON.parse(file.contents.toString('utf8'));
if (product.extensionsGallery) {
console.error('product.json: Contains "extensionsGallery"');
errorCount++;
}
this.emit('data', file);
});
const indentation = es.through(function (file) {
const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/);
file.__lines = lines;
@ -258,8 +269,13 @@ function hygiene(some) {
input = some;
}
const productJsonFilter = filter('product.json', { restore: true });
const result = input
.pipe(filter(f => !f.stat.isDirectory()))
.pipe(productJsonFilter)
.pipe(process.env['BUILD_SOURCEVERSION'] ? es.through() : productJson)
.pipe(productJsonFilter.restore)
.pipe(filter(indentationFilter))
.pipe(indentation)
.pipe(filter(copyrightFilter))

View file

@ -315,6 +315,8 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
// TODO the API should be copied to `out` during compile, not here
const api = gulp.src('src/vs/vscode.d.ts').pipe(rename('out/vs/vscode.d.ts'));
const telemetry = gulp.src('.build/telemetry/**', { base: '.build/telemetry', dot: true });
const depsSrc = [
..._.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])),
// @ts-ignore JSON checking: dependencies is optional
@ -327,10 +329,11 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar'));
let all = es.merge(
packageJsonStream,
packageJsonStream,
productJsonStream,
license,
api,
telemetry,
sources,
deps
);
@ -380,7 +383,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
.pipe(util.skipDirectories())
.pipe(util.fixWin32DirectoryPermissions())
.pipe(electron(_.extend({}, config, { platform, arch, ffmpegChromium: true })))
.pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version']));
.pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version'], { dot: true }));
// result = es.merge(result, gulp.src('resources/completions/**', { base: '.' }));

View file

@ -20,13 +20,10 @@ function yarnInstall(location, opts) {
const raw = process.env['npm_config_argv'] || '{}';
const argv = JSON.parse(raw);
const original = argv.original || [];
const args = ['install'];
const args = original.filter(arg => arg === '--ignore-optional' || arg === '--frozen-lockfile');
if (original.indexOf('--ignore-optional') > -1) {
args.push('--ignore-optional');
}
console.log('Installing dependencies in \'%s\'.', location);
console.log(`Installing dependencies in ${location}...`);
console.log(`$ yarn ${args.join(' ')}`);
const result = cp.spawnSync(yarn, args, opts);
if (result.error || result.status !== 0) {

View file

@ -1034,7 +1034,7 @@ begin
AltArch := '32';
end;
if not Result then begin
if not Result and not WizardSilent() then begin
MsgBox('Please uninstall the ' + AltArch + '-bit version of {#NameShort} before installing this ' + ThisArch + '-bit version.', mbInformation, MB_OK);
end;
end;

View file

@ -60,12 +60,12 @@
"git": {
"name": "electron",
"repositoryUrl": "https://github.com/electron/electron",
"commitHash": "c1b5a1cfc8a14a337540193daecfa5d0f50dd7bb"
"commitHash": "5d67ec3da5376a5058990e8a9557bc9124ad59a8"
}
},
"isOnlyProductionDependency": true,
"license": "MIT",
"version": "4.2.4"
"version": "4.2.5"
},
{
"component": {

View file

@ -488,7 +488,10 @@ class DotGitWatcher implements IFileWatcher {
private transientDisposables: IDisposable[] = [];
private disposables: IDisposable[] = [];
constructor(private repository: Repository) {
constructor(
private repository: Repository,
private outputChannel: OutputChannel
) {
const rootWatcher = watch(repository.dotGit);
this.disposables.push(rootWatcher);
@ -511,9 +514,15 @@ class DotGitWatcher implements IFileWatcher {
const { name, remote } = this.repository.HEAD.upstream;
const upstreamPath = path.join(this.repository.dotGit, 'refs', 'remotes', remote, name);
const upstreamWatcher = watch(upstreamPath);
this.transientDisposables.push(upstreamWatcher);
upstreamWatcher.event(this.emitter.fire, this.emitter, this.transientDisposables);
try {
const upstreamWatcher = watch(upstreamPath);
this.transientDisposables.push(upstreamWatcher);
upstreamWatcher.event(this.emitter.fire, this.emitter, this.transientDisposables);
} catch (err) {
if (env.logLevel <= LogLevel.Info) {
this.outputChannel.appendLine(`Failed to watch ref '${upstreamPath}'. Ref is most likely packed.`);
}
}
}
dispose() {
@ -642,7 +651,7 @@ export class Repository implements Disposable {
const onWorkspaceRepositoryFileChange = filterEvent(onWorkspaceFileChange, uri => isDescendant(repository.root, uri.fsPath));
const onWorkspaceWorkingTreeFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => !/\/\.git($|\/)/.test(uri.path));
const dotGitFileWatcher = new DotGitWatcher(this);
const dotGitFileWatcher = new DotGitWatcher(this, outputChannel);
this.disposables.push(dotGitFileWatcher);
// FS changes should trigger `git status`:
@ -664,9 +673,9 @@ export class Repository implements Disposable {
this._sourceControl.inputBox.validateInput = this.validateInput.bind(this);
this.disposables.push(this._sourceControl);
this._mergeGroup = this._sourceControl.createResourceGroup('merge', localize('merge changes', "Merge Changes"));
this._indexGroup = this._sourceControl.createResourceGroup('index', localize('staged changes', "Staged Changes"));
this._workingTreeGroup = this._sourceControl.createResourceGroup('workingTree', localize('changes', "Changes"));
this._mergeGroup = this._sourceControl.createResourceGroup('merge', localize('merge changes', "MERGE CHANGES"));
this._indexGroup = this._sourceControl.createResourceGroup('index', localize('staged changes', "STAGED CHANGES"));
this._workingTreeGroup = this._sourceControl.createResourceGroup('workingTree', localize('changes', "CHANGES"));
const updateIndexGroupVisibility = () => {
const config = workspace.getConfiguration('git', root);

View file

@ -24,7 +24,6 @@
".bowerrc",
".jshintrc",
".jscsrc",
".eslintrc",
".swcrc",
".webmanifest",
".js.map",
@ -49,7 +48,9 @@
"extensions": [
".hintrc",
".babelrc",
".jsonc"
".jsonc",
".eslintrc",
".eslintrc.json"
],
"configuration": "./language-configuration.json"
}

View file

@ -39,7 +39,7 @@ function parseLink(
return {
uri: OpenDocumentLinkCommand.createCommandUri(resourcePath, tempUri.fragment),
tooltip: localize('documentLink.tooltip', 'follow link')
tooltip: localize('documentLink.tooltip', 'Follow link')
};
}

View file

@ -412,7 +412,7 @@ export class MarkdownPreview extends Disposable {
this.currentVersion = pendingVersion;
if (this._resource === resource) {
const content = await this._contentProvider.provideTextDocumentContent(document, this._previewConfigurations, this.line, this.state);
const content = await this._contentProvider.provideTextDocumentContent(document, await this.editor.webview.resourceRoot, this._previewConfigurations, this.line, this.state);
// Another call to `doUpdate` may have happened.
// Make sure we are still updating for the correct document
if (this.currentVersion && this.currentVersion.equals(pendingVersion)) {

View file

@ -51,6 +51,7 @@ export class MarkdownContentProvider {
public async provideTextDocumentContent(
markdownDocument: vscode.TextDocument,
webviewResourceRoot: string,
previewConfigurations: MarkdownPreviewConfigurationManager,
initialLine: number | undefined = undefined,
state?: any
@ -65,14 +66,14 @@ export class MarkdownContentProvider {
scrollEditorWithPreview: config.scrollEditorWithPreview,
doubleClickToSwitchToEditor: config.doubleClickToSwitchToEditor,
disableSecurityWarnings: this.cspArbiter.shouldDisableSecurityWarnings(),
webviewResourceRoot: vscode.env.webviewResourceRoot,
webviewResourceRoot: webviewResourceRoot,
};
this.logger.log('provideTextDocumentContent', initialData);
// Content Security Policy
const nonce = new Date().getTime() + '' + new Date().getMilliseconds();
const csp = this.getCspForResource(sourceUri, nonce);
const csp = this.getCspForResource(webviewResourceRoot, sourceUri, nonce);
const body = await this.engine.render(markdownDocument);
return `<!DOCTYPE html>
@ -84,14 +85,14 @@ export class MarkdownContentProvider {
data-settings="${escapeAttribute(JSON.stringify(initialData))}"
data-strings="${escapeAttribute(JSON.stringify(previewStrings))}"
data-state="${escapeAttribute(JSON.stringify(state || {}))}">
<script src="${this.extensionResourcePath('pre.js')}" nonce="${nonce}"></script>
${this.getStyles(sourceUri, nonce, config, state)}
<base href="${toResoruceUri(markdownDocument.uri)}">
<script src="${this.extensionResourcePath(webviewResourceRoot, 'pre.js')}" nonce="${nonce}"></script>
${this.getStyles(webviewResourceRoot, sourceUri, nonce, config, state)}
<base href="${toResoruceUri(webviewResourceRoot, markdownDocument.uri)}">
</head>
<body class="vscode-body ${config.scrollBeyondLastLine ? 'scrollBeyondLastLine' : ''} ${config.wordWrap ? 'wordWrap' : ''} ${config.markEditorSelection ? 'showEditorSelection' : ''}">
${body}
<div class="code-line" data-line="${markdownDocument.lineCount}"></div>
${this.getScripts(nonce)}
${this.getScripts(webviewResourceRoot, nonce)}
</body>
</html>`;
}
@ -109,12 +110,12 @@ export class MarkdownContentProvider {
</html>`;
}
private extensionResourcePath(mediaFile: string): string {
return toResoruceUri(vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile))))
private extensionResourcePath(webviewResourceRoot: string, mediaFile: string): string {
return toResoruceUri(webviewResourceRoot, vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile))))
.toString();
}
private fixHref(resource: vscode.Uri, href: string): string {
private fixHref(webviewResourceRoot: string, resource: vscode.Uri, href: string): string {
if (!href) {
return href;
}
@ -125,23 +126,23 @@ export class MarkdownContentProvider {
// Assume it must be a local file
if (path.isAbsolute(href)) {
return toResoruceUri(vscode.Uri.file(href)).toString();
return toResoruceUri(webviewResourceRoot, vscode.Uri.file(href)).toString();
}
// Use a workspace relative path if there is a workspace
const root = vscode.workspace.getWorkspaceFolder(resource);
if (root) {
return toResoruceUri(vscode.Uri.file(path.join(root.uri.fsPath, href))).toString();
return toResoruceUri(webviewResourceRoot, vscode.Uri.file(path.join(root.uri.fsPath, href))).toString();
}
// Otherwise look relative to the markdown file
return toResoruceUri(vscode.Uri.file(path.join(path.dirname(resource.fsPath), href))).toString();
return toResoruceUri(webviewResourceRoot, vscode.Uri.file(path.join(path.dirname(resource.fsPath), href))).toString();
}
private computeCustomStyleSheetIncludes(resource: vscode.Uri, config: MarkdownPreviewConfiguration): string {
private computeCustomStyleSheetIncludes(webviewResourceRoot: string, resource: vscode.Uri, config: MarkdownPreviewConfiguration): string {
if (Array.isArray(config.styles)) {
return config.styles.map(style => {
return `<link rel="stylesheet" class="code-user-style" data-source="${escapeAttribute(style)}" href="${escapeAttribute(this.fixHref(resource, style))}" type="text/css" media="screen">`;
return `<link rel="stylesheet" class="code-user-style" data-source="${escapeAttribute(style)}" href="${escapeAttribute(this.fixHref(webviewResourceRoot, resource, style))}" type="text/css" media="screen">`;
}).join('\n');
}
return '';
@ -172,37 +173,41 @@ export class MarkdownContentProvider {
return ret;
}
private getStyles(resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfiguration, state?: any): string {
private getStyles(webviewResourceRoot: string, resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfiguration, state?: any): string {
const baseStyles = this.contributionProvider.contributions.previewStyles
.map(resource => `<link rel="stylesheet" type="text/css" href="${escapeAttribute(resource.toString())}">`)
.map(resource => `<link rel="stylesheet" type="text/css" href="${escapeAttribute(toResoruceUri(webviewResourceRoot, resource).toString())}">`)
.join('\n');
return `${baseStyles}
${this.getSettingsOverrideStyles(nonce, config)}
${this.computeCustomStyleSheetIncludes(resource, config)}
${this.computeCustomStyleSheetIncludes(webviewResourceRoot, resource, config)}
${this.getImageStabilizerStyles(state)}`;
}
private getScripts(nonce: string): string {
private getScripts(resourceRoot: string, nonce: string): string {
return this.contributionProvider.contributions.previewScripts
.map(resource => `<script async src="${escapeAttribute(resource.toString())}" nonce="${nonce}" charset="UTF-8"></script>`)
.map(resource => `<script async src="${escapeAttribute(toResoruceUri(resourceRoot, resource).toString())}" nonce="${nonce}" charset="UTF-8"></script>`)
.join('\n');
}
private getCspForResource(resource: vscode.Uri, nonce: string): string {
private getCspForResource(
webviewResourceRoot: string,
resource: vscode.Uri,
nonce: string
): string {
switch (this.cspArbiter.getSecurityLevelForResource(resource)) {
case MarkdownPreviewSecurityLevel.AllowInsecureContent:
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${vscode.env.webviewResourceRoot} http: https: data:; media-src 'self' ${vscode.env.webviewResourceRoot} http: https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${vscode.env.webviewResourceRoot} 'unsafe-inline' http: https: data:; font-src 'self' ${vscode.env.webviewResourceRoot} http: https: data:;">`;
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${webviewResourceRoot} http: https: data:; media-src 'self' ${webviewResourceRoot} http: https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${webviewResourceRoot} 'unsafe-inline' http: https: data:; font-src 'self' ${webviewResourceRoot} http: https: data:;">`;
case MarkdownPreviewSecurityLevel.AllowInsecureLocalContent:
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${vscode.env.webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*; media-src 'self' ${vscode.env.webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*; script-src 'nonce-${nonce}'; style-src 'self' ${vscode.env.webviewResourceRoot} 'unsafe-inline' https: data: http://localhost:* http://127.0.0.1:*; font-src 'self' ${vscode.env.webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*;">`;
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*; media-src 'self' ${webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*; script-src 'nonce-${nonce}'; style-src 'self' ${webviewResourceRoot} 'unsafe-inline' https: data: http://localhost:* http://127.0.0.1:*; font-src 'self' ${webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*;">`;
case MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent:
return '';
case MarkdownPreviewSecurityLevel.Strict:
default:
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${vscode.env.webviewResourceRoot} https: data:; media-src 'self' ${vscode.env.webviewResourceRoot} https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${vscode.env.webviewResourceRoot} 'unsafe-inline' https: data:; font-src 'self' ${vscode.env.webviewResourceRoot} https: data:;">`;
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${webviewResourceRoot} https: data:; media-src 'self' ${webviewResourceRoot} https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${webviewResourceRoot} 'unsafe-inline' https: data:; font-src 'self' ${webviewResourceRoot} https: data:;">`;
}
}
}

View file

@ -7,10 +7,9 @@ import * as vscode from 'vscode';
import * as path from 'path';
import { Disposable } from './util/dispose';
import * as arrays from './util/arrays';
import { toResoruceUri } from './util/resources';
const resolveExtensionResource = (extension: vscode.Extension<any>, resourcePath: string): vscode.Uri => {
return toResoruceUri(vscode.Uri.file(path.join(extension.extensionPath, resourcePath)));
return vscode.Uri.file(path.join(extension.extensionPath, resourcePath));
};
const resolveExtensionResources = (extension: vscode.Extension<any>, resourcePaths: unknown): vscode.Uri[] => {

View file

@ -5,9 +5,9 @@
import * as vscode from 'vscode';
const rootUri = vscode.Uri.parse(vscode.env.webviewResourceRoot);
export function toResoruceUri(uri: vscode.Uri): vscode.Uri {
export function toResoruceUri(webviewResourceRoot: string, uri: vscode.Uri): vscode.Uri {
const rootUri = vscode.Uri.parse(webviewResourceRoot);
return rootUri.with({
path: rootUri.path + uri.path,
query: uri.query,

View file

@ -49,7 +49,7 @@
"typescript.problemMatchers.tsc.label": "TypeScript problems",
"typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)",
"configuration.suggest.paths": "Enable/disable suggestions for paths in import statements and require calls.",
"configuration.experimental.useSeparateSyntaxServer": "Enable/disable spawning a separate TypeScript server that can more quickly respond to syntax related operations, such as calculating folding or computing document symbols. Note that you must restart the TypeScript server after changing this setting. Requires using TypeScript 3.4.0 or newer in the workspace.",
"configuration.experimental.useSeparateSyntaxServer": "Enable/disable spawning a separate TypeScript server that can more quickly respond to syntax related operations, such as calculating folding or computing document symbols. Requires using TypeScript 3.4.0 or newer in the workspace.",
"typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Requires using TypeScript 2.6.0 or newer in the workspace. Default of `null` uses VS Code's locale.",
"javascript.implicitProjectConfig.experimentalDecorators": "Enable/disable `experimentalDecorators` for JavaScript files that are not part of a project. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.",
"configuration.suggest.autoImports": "Enable/disable auto import suggestions. Requires using TypeScript 2.6.1 or newer in the workspace.",

View file

@ -234,8 +234,10 @@ class TscTaskProvider implements vscode.TaskProvider {
private getLabelForTasks(project: TSConfig): string {
if (project.workspaceFolder) {
return path.posix.relative(project.workspaceFolder.uri.path, project.posixPath);
const workspaceNormalizedUri = vscode.Uri.file(path.normalize(project.workspaceFolder.uri.fsPath)); // Make sure the drive letter is lowercase
return path.posix.relative(workspaceNormalizedUri.path, project.posixPath);
}
return project.posixPath;
}

View file

@ -340,6 +340,7 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ
'selectionRange',
'format',
'formatonkey',
'docCommentTemplate',
]);
private static readonly sharedCommands = new Set<keyof TypeScriptRequests>([
'change',
@ -357,8 +358,34 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ
return this.syntaxServer.executeImpl(command, args, executeInfo);
} else if (SyntaxRoutingTsServer.sharedCommands.has(command)) {
// Dispatch to both server but only return from syntax one
this.semanticServer.executeImpl(command, args, executeInfo);
return this.syntaxServer.executeImpl(command, args, executeInfo);
// Also make sure we never cancel requests to just one server
let hasCompletedSyntax = false;
let hasCompletedSemantic = false;
let token: vscode.CancellationToken | undefined = undefined;
if (executeInfo.token) {
const source = new vscode.CancellationTokenSource();
executeInfo.token.onCancellationRequested(() => {
if (hasCompletedSyntax && !hasCompletedSemantic || hasCompletedSemantic && !hasCompletedSyntax) {
// Don't cancel.
// One of the servers completed this request so we don't want to leave the other
// in a different state
return;
}
source.cancel();
});
token = source.token;
}
const semanticRequest = this.semanticServer.executeImpl(command, args, { ...executeInfo, token });
if (semanticRequest) {
semanticRequest.finally(() => { hasCompletedSemantic = true; });
}
const syntaxRequest = this.syntaxServer.executeImpl(command, args, { ...executeInfo, token });
if (syntaxRequest) {
syntaxRequest.finally(() => { hasCompletedSyntax = true; });
}
return syntaxRequest;
} else {
return this.semanticServer.executeImpl(command, args, executeInfo);
}

View file

@ -37,7 +37,7 @@ export class TypeScriptServerSpawner {
configuration: TypeScriptServiceConfiguration,
pluginManager: PluginManager
): ITypeScriptServer {
if (this.shouldUseSeparateSyntaxServer(version)) {
if (this.shouldUseSeparateSyntaxServer(version, configuration)) {
const syntaxServer = this.spawnTsServer('syntax', version, configuration, pluginManager);
const semanticServer = this.spawnTsServer('semantic', version, configuration, pluginManager);
return new SyntaxRoutingTsServer(syntaxServer, semanticServer);
@ -46,12 +46,11 @@ export class TypeScriptServerSpawner {
return this.spawnTsServer('main', version, configuration, pluginManager);
}
private shouldUseSeparateSyntaxServer(version: TypeScriptVersion): boolean {
if (!version.apiVersion || version.apiVersion.lt(API.v340)) {
return false;
}
return vscode.workspace.getConfiguration('typescript')
.get<boolean>('experimental.useSeparateSyntaxServer', false);
private shouldUseSeparateSyntaxServer(
version: TypeScriptVersion,
configuration: TypeScriptServiceConfiguration,
): boolean {
return configuration.useSeparateSyntaxServer && !!version.apiVersion && version.apiVersion.gte(API.v340);
}
private spawnTsServer(

View file

@ -25,7 +25,7 @@ import Tracer from './utils/tracer';
import { inferredProjectConfig } from './utils/tsconfig';
import { TypeScriptVersionPicker } from './utils/versionPicker';
import { TypeScriptVersion, TypeScriptVersionProvider } from './utils/versionProvider';
import { TypeScriptServerSpawner } from './tsServer/spanwer';
import { TypeScriptServerSpawner } from './tsServer/spawner';
const localize = nls.loadMessageBundle();

View file

@ -54,6 +54,7 @@ export class TypeScriptServiceConfiguration {
public readonly checkJs: boolean;
public readonly experimentalDecorators: boolean;
public readonly disableAutomaticTypeAcquisition: boolean;
public readonly useSeparateSyntaxServer: boolean;
public static loadFromWorkspace(): TypeScriptServiceConfiguration {
return new TypeScriptServiceConfiguration();
@ -71,6 +72,7 @@ export class TypeScriptServiceConfiguration {
this.checkJs = TypeScriptServiceConfiguration.readCheckJs(configuration);
this.experimentalDecorators = TypeScriptServiceConfiguration.readExperimentalDecorators(configuration);
this.disableAutomaticTypeAcquisition = TypeScriptServiceConfiguration.readDisableAutomaticTypeAcquisition(configuration);
this.useSeparateSyntaxServer = TypeScriptServiceConfiguration.readUseSeparateSyntaxServer(configuration);
}
public isEqualTo(other: TypeScriptServiceConfiguration): boolean {
@ -82,7 +84,8 @@ export class TypeScriptServiceConfiguration {
&& this.checkJs === other.checkJs
&& this.experimentalDecorators === other.experimentalDecorators
&& this.disableAutomaticTypeAcquisition === other.disableAutomaticTypeAcquisition
&& arrays.equals(this.tsServerPluginPaths, other.tsServerPluginPaths);
&& arrays.equals(this.tsServerPluginPaths, other.tsServerPluginPaths)
&& this.useSeparateSyntaxServer === other.useSeparateSyntaxServer;
}
private static fixPathPrefixes(inspectValue: string): string {
@ -139,4 +142,8 @@ export class TypeScriptServiceConfiguration {
private static extractLocale(configuration: vscode.WorkspaceConfiguration): string | null {
return configuration.get<string | null>('typescript.locale', null);
}
private static readUseSeparateSyntaxServer(configuration: vscode.WorkspaceConfiguration): boolean {
return configuration.get<boolean>('typescript.experimental.useSeparateSyntaxServer', false);
}
}

View file

@ -7,13 +7,14 @@ import * as temp from './temp';
import path = require('path');
import fs = require('fs');
import cp = require('child_process');
import process = require('process');
const getRootTempDir = (() => {
let dir: string | undefined;
return () => {
if (!dir) {
dir = temp.getTempFile(`vscode-typescript`);
dir = temp.getTempFile(`vscode-typescript${process.platform !== 'win32' && process.getuid ? process.getuid() : ''}`);
}
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);

View file

@ -9,7 +9,6 @@ import { RelativeWorkspacePathResolver } from './relativePathResolver';
export class TypeScriptPluginPathsProvider {
public readonly relativePathResolver: RelativeWorkspacePathResolver = new RelativeWorkspacePathResolver();
public constructor(
private configuration: TypeScriptServiceConfiguration
@ -32,7 +31,7 @@ export class TypeScriptPluginPathsProvider {
return [pluginPath];
}
const workspacePath = this.relativePathResolver.asAbsoluteWorkspacePath(pluginPath);
const workspacePath = RelativeWorkspacePathResolver.asAbsoluteWorkspacePath(pluginPath);
if (workspacePath !== undefined) {
return [workspacePath];
}

View file

@ -6,7 +6,7 @@ import * as path from 'path';
import * as vscode from 'vscode';
export class RelativeWorkspacePathResolver {
public asAbsoluteWorkspacePath(relativePath: string): string | undefined {
public static asAbsoluteWorkspacePath(relativePath: string): string | undefined {
for (const root of vscode.workspace.workspaceFolders || []) {
const rootPrefixes = [`./${root.name}/`, `${root.name}/`, `.\\${root.name}\\`, `${root.name}\\`];
for (const rootPrefix of rootPrefixes) {

View file

@ -113,7 +113,7 @@ export class TypeScriptVersionPicker {
return { oldVersion: previousVersion, newVersion: shippedVersion };
case MessageAction.learnMore:
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=839919'));
vscode.env.openExternal(vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=839919'));
return { oldVersion: this.currentVersion };
default:

View file

@ -88,7 +88,6 @@ export class TypeScriptVersion {
}
export class TypeScriptVersionProvider {
private readonly relativePathResolver: RelativeWorkspacePathResolver = new RelativeWorkspacePathResolver();
public constructor(
private configuration: TypeScriptServiceConfiguration
@ -179,7 +178,7 @@ export class TypeScriptVersionProvider {
return [new TypeScriptVersion(tsdkPathSetting)];
}
const workspacePath = this.relativePathResolver.asAbsoluteWorkspacePath(tsdkPathSetting);
const workspacePath = RelativeWorkspacePathResolver.asAbsoluteWorkspacePath(tsdkPathSetting);
if (workspacePath !== undefined) {
return [new TypeScriptVersion(workspacePath, tsdkPathSetting)];
}

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { env } from 'vscode';
import { env, extensions, ExtensionKind } from 'vscode';
suite('env-namespace', () => {
@ -24,4 +24,22 @@ suite('env-namespace', () => {
assert.throws(() => (env as any).sessionId = '234');
});
test('env.remoteName', function () {
const remoteName = env.remoteName;
const apiTestExtension = extensions.getExtension('vscode.vscode-api-tests');
const testResolverExtension = extensions.getExtension('vscode.vscode-test-resolver');
if (typeof remoteName === 'undefined') {
assert.ok(apiTestExtension);
assert.ok(testResolverExtension);
assert.equal(ExtensionKind.UI, apiTestExtension!.extensionKind);
assert.equal(ExtensionKind.UI, testResolverExtension!.extensionKind);
} else if (typeof remoteName === 'string') {
assert.ok(apiTestExtension);
assert.ok(!testResolverExtension); // we currently can only access extensions that run on same host
assert.equal(ExtensionKind.Workspace, apiTestExtension!.extensionKind);
} else {
assert.fail();
}
});
});

View file

@ -251,7 +251,7 @@ suite('Webview tests', () => {
});
</script>`);
const workspaceRootUri = vscode.env.webviewResourceRoot + vscode.Uri.file(vscode.workspace.rootPath!).path;
const workspaceRootUri = webview.webview.resourceRoot + vscode.Uri.file(vscode.workspace.rootPath!).path;
{
const imagePath = workspaceRootUri.toString() + '/image.png';

View file

@ -738,8 +738,8 @@ suite('window namespace tests', () => {
terminal1.show();
});
test('runInBackground terminal: onDidWriteData should work', done => {
const terminal = window.createTerminal({ name: 'bg', runInBackground: true });
test('hideFromUser terminal: onDidWriteData should work', done => {
const terminal = window.createTerminal({ name: 'bg', hideFromUser: true });
let data = '';
terminal.onDidWriteData(e => {
data += e;
@ -751,8 +751,8 @@ suite('window namespace tests', () => {
terminal.sendText('foo');
});
test('runInBackground terminal: should be available to terminals API', done => {
const terminal = window.createTerminal({ name: 'bg', runInBackground: true });
test('hideFromUser terminal: should be available to terminals API', done => {
const terminal = window.createTerminal({ name: 'bg', hideFromUser: true });
window.onDidOpenTerminal(t => {
assert.equal(t, terminal);
assert.equal(t.name, 'bg');

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.36.0",
"distro": "05595573cc7515041a708d6ba0596dfeef29c250",
"version": "1.37.0",
"distro": "b49e556c274bfe2fc7f4fafd3804cb4ebd948c4f",
"author": {
"name": "Microsoft Corporation"
},

View file

@ -14,6 +14,7 @@ arguments=(
'--user-data-dir[specify the directory that user data is kept in]:directory:_directories'
'(- *)'{-v,--version}'[print version]'
'(- *)'{-h,--help}'[print usage]'
'(- *)'{--telemetry}'[Shows all telemetry events which VS code collects.]'
'--extensions-dir[set the root path for extensions]:root path:_directories'
'--list-extensions[list the installed extensions]'
'--show-versions[show versions of installed extensions, when using --list-extension]'

View file

@ -16,7 +16,7 @@ if grep -qi Microsoft /proc/version; then
WSL_BUILD=18362
else
WSL_BUILD=$(uname -r | sed -E 's/^.+-([0-9]+)-Microsoft/\1/')
if ! [ -z "$WSL_BUILD" ]; then
if [ -z "$WSL_BUILD" ]; then
WSL_BUILD=0
fi
fi

View file

@ -10,25 +10,25 @@ call .\scripts\test.bat --runGlob **\*.integrationTest.js %*
if %errorlevel% neq 0 exit /b %errorlevel%
:: Tests in the extension host
call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR%
if %errorlevel% neq 0 exit /b %errorlevel%
call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR%
if %errorlevel% neq 0 exit /b %errorlevel%
call .\scripts\code.bat %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
call .\scripts\code.bat %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR%
if %errorlevel% neq 0 exit /b %errorlevel%
call .\scripts\code.bat $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
call .\scripts\code.bat $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% .
if %errorlevel% neq 0 exit /b %errorlevel%
:: Tests in commonJS (HTML, CSS, JSON language server tests...)
call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js
if %errorlevel% neq 0 exit /b %errorlevel%
REM if exist ".\resources\server\test\test-remote-integration.bat" (
REM call .\resources\server\test\test-remote-integration.bat
REM )
if exist ".\resources\server\test\test-remote-integration.bat" (
call .\resources\server\test\test-remote-integration.bat
)
rmdir /s /q %VSCODEUSERDATADIR%

View file

@ -16,13 +16,13 @@ cd $ROOT
./scripts/test.sh --runGlob **/*.integrationTest.js "$@"
# Tests in the extension host
./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR
./scripts/code.sh $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR
./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR
./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR
mkdir -p $ROOT/extensions/emmet/test-fixtures
./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR
rm -rf $ROOT/extensions/emmet/test-fixtures
if [ -f ./resources/server/test/test-remote-integration.sh ]; then

View file

@ -1,4 +1,4 @@
// Type definitions for Electron 4.2.4
// Type definitions for Electron 4.2.5
// Project: http://electronjs.org/
// Definitions by: The Electron Team <https://github.com/electron/electron>
// Definitions: https://github.com/electron/electron-typescript-definitions

View file

@ -122,6 +122,7 @@ export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0));
export const isWebkitWebView = (!isChrome && !isSafari && isWebKit);
export const isIPad = (userAgent.indexOf('iPad') >= 0);
export const isEdgeWebView = isEdge && (userAgent.indexOf('WebView/') >= 0);
export const isStandalone = (window.matchMedia('(display-mode: standalone)').matches);
export function hasClipboardSupport() {
if (isIE) {

View file

@ -858,6 +858,7 @@ export const EventType = {
RESIZE: 'resize',
SCROLL: 'scroll',
FULLSCREEN_CHANGE: 'fullscreenchange',
WK_FULLSCREEN_CHANGE: 'webkitfullscreenchange',
// Form
SELECT: 'select',
CHANGE: 'change',

View file

@ -108,6 +108,10 @@ export class BaseDropdown extends ActionRunner {
this.visible = false;
}
isVisible(): boolean {
return this.visible;
}
protected onEvent(e: Event, activeElement: HTMLElement): void {
this.hide();
}

View file

@ -18,7 +18,7 @@ import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEle
import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
import { Event, Emitter } from 'vs/base/common/event';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { isLinux } from 'vs/base/common/platform';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
function createMenuMnemonicRegExp() {
try {
@ -91,7 +91,7 @@ export class Menu extends ActionBar {
context: options.context,
actionRunner: options.actionRunner,
ariaLabel: options.ariaLabel,
triggerKeys: { keys: [KeyCode.Enter], keyDown: true }
triggerKeys: { keys: [KeyCode.Enter, ...(isMacintosh ? [KeyCode.Space] : [])], keyDown: true }
});
this.menuElement = menuElement;
@ -109,7 +109,7 @@ export class Menu extends ActionBar {
// Stop tab navigation of menus
if (event.equals(KeyCode.Tab)) {
EventHelper.stop(e, true);
e.preventDefault();
}
});

View file

@ -14,11 +14,12 @@ import { cleanMnemonic, IMenuOptions, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MN
import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions';
import { RunOnceScheduler } from 'vs/base/common/async';
import { Event, Emitter } from 'vs/base/common/event';
import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { KeyCode, ResolvedKeybinding, KeyMod } from 'vs/base/common/keyCodes';
import { Disposable, dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { withNullAsUndefined } from 'vs/base/common/types';
import { asArray } from 'vs/base/common/arrays';
import { ScanCodeUtils, ScanCode } from 'vs/base/common/scanCode';
import { isMacintosh } from 'vs/base/common/platform';
const $ = DOM.$;
@ -116,9 +117,9 @@ export class MenuBar extends Disposable {
let eventHandled = true;
const key = !!e.key ? e.key.toLocaleLowerCase() : '';
if (event.equals(KeyCode.LeftArrow)) {
if (event.equals(KeyCode.LeftArrow) || (isMacintosh && event.equals(KeyCode.Tab | KeyMod.Shift))) {
this.focusPrevious();
} else if (event.equals(KeyCode.RightArrow)) {
} else if (event.equals(KeyCode.RightArrow) || (isMacintosh && event.equals(KeyCode.Tab))) {
this.focusNext();
} else if (event.equals(KeyCode.Escape) && this.isFocused && !this.isOpen) {
this.setUnfocusedState();
@ -129,6 +130,11 @@ export class MenuBar extends Disposable {
eventHandled = false;
}
// Never allow default tab behavior
if (event.equals(KeyCode.Tab | KeyMod.Shift) || event.equals(KeyCode.Tab)) {
event.preventDefault();
}
if (eventHandled) {
event.preventDefault();
event.stopPropagation();

View file

@ -225,6 +225,7 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
}
},
keyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && {
...options.keyboardNavigationLabelProvider,
getKeyboardNavigationLabel(e) {
return options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e.element as T);
}

View file

@ -78,7 +78,10 @@ export class VSBuffer {
}
slice(start?: number, end?: number): VSBuffer {
return new VSBuffer(this.buffer.slice(start, end));
// IMPORTANT: use subarray instead of slice because TypedArray#slice
// creates shallow copy and NodeBuffer#slice doesn't. The use of subarray
// ensures the same, performant, behaviour.
return new VSBuffer(this.buffer.subarray(start!/*bad lib.d.ts*/, end));
}
set(array: VSBuffer, offset?: number): void {
@ -437,4 +440,4 @@ class VSBufferWriteableStreamImpl implements VSBufferWriteableStream {
this.listeners.end.length = 0;
}
}
}
}

View file

@ -7,28 +7,26 @@ import * as strings from 'vs/base/common/strings';
import { sep } from 'vs/base/common/path';
import { IdleValue } from 'vs/base/common/async';
let intlFileNameCollator: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }>;
export function setFileNameComparer(collator: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }>): void {
intlFileNameCollator = collator;
}
const intlFileNameCollator: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }> = new IdleValue(() => {
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
return {
collator: collator,
collatorIsNumeric: collator.resolvedOptions().numeric
};
});
export function compareFileNames(one: string | null, other: string | null, caseSensitive = false): number {
if (intlFileNameCollator) {
const a = one || '';
const b = other || '';
const result = intlFileNameCollator.getValue().collator.compare(a, b);
const a = one || '';
const b = other || '';
const result = intlFileNameCollator.getValue().collator.compare(a, b);
// Using the numeric option in the collator will
// make compare(`foo1`, `foo01`) === 0. We must disambiguate.
if (intlFileNameCollator.getValue().collatorIsNumeric && result === 0 && a !== b) {
return a < b ? -1 : 1;
}
return result;
// Using the numeric option in the collator will
// make compare(`foo1`, `foo01`) === 0. We must disambiguate.
if (intlFileNameCollator.getValue().collatorIsNumeric && result === 0 && a !== b) {
return a < b ? -1 : 1;
}
return noIntlCompareFileNames(one, other, caseSensitive);
return result;
}
const FileNameMatch = /^(.*?)(\.([^.]*))?$/;
@ -54,46 +52,27 @@ export function noIntlCompareFileNames(one: string | null, other: string | null,
}
export function compareFileExtensions(one: string | null, other: string | null): number {
if (intlFileNameCollator) {
const [oneName, oneExtension] = extractNameAndExtension(one);
const [otherName, otherExtension] = extractNameAndExtension(other);
const [oneName, oneExtension] = extractNameAndExtension(one);
const [otherName, otherExtension] = extractNameAndExtension(other);
let result = intlFileNameCollator.getValue().collator.compare(oneExtension, otherExtension);
let result = intlFileNameCollator.getValue().collator.compare(oneExtension, otherExtension);
if (result === 0) {
// Using the numeric option in the collator will
// make compare(`foo1`, `foo01`) === 0. We must disambiguate.
if (intlFileNameCollator.getValue().collatorIsNumeric && oneExtension !== otherExtension) {
return oneExtension < otherExtension ? -1 : 1;
}
// Extensions are equal, compare filenames
result = intlFileNameCollator.getValue().collator.compare(oneName, otherName);
if (intlFileNameCollator.getValue().collatorIsNumeric && result === 0 && oneName !== otherName) {
return oneName < otherName ? -1 : 1;
}
if (result === 0) {
// Using the numeric option in the collator will
// make compare(`foo1`, `foo01`) === 0. We must disambiguate.
if (intlFileNameCollator.getValue().collatorIsNumeric && oneExtension !== otherExtension) {
return oneExtension < otherExtension ? -1 : 1;
}
return result;
// Extensions are equal, compare filenames
result = intlFileNameCollator.getValue().collator.compare(oneName, otherName);
if (intlFileNameCollator.getValue().collatorIsNumeric && result === 0 && oneName !== otherName) {
return oneName < otherName ? -1 : 1;
}
}
return noIntlCompareFileExtensions(one, other);
}
function noIntlCompareFileExtensions(one: string | null, other: string | null): number {
const [oneName, oneExtension] = extractNameAndExtension(one && one.toLowerCase());
const [otherName, otherExtension] = extractNameAndExtension(other && other.toLowerCase());
if (oneExtension !== otherExtension) {
return oneExtension < otherExtension ? -1 : 1;
}
if (oneName === otherName) {
return 0;
}
return oneName < otherName ? -1 : 1;
return result;
}
function extractNameAndExtension(str?: string | null): [string, string] {

View file

@ -3,23 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { compareFileNames, compareFileExtensions, setFileNameComparer } from 'vs/base/common/comparers';
import { compareFileNames, compareFileExtensions } from 'vs/base/common/comparers';
import * as assert from 'assert';
import { IdleValue } from 'vs/base/common/async';
suite('Comparers', () => {
test('compareFileNames', () => {
// Setup Intl
setFileNameComparer(new IdleValue(() => {
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
return {
collator: collator,
collatorIsNumeric: collator.resolvedOptions().numeric
};
}));
assert(compareFileNames(null, null) === 0, 'null should be equal');
assert(compareFileNames(null, 'abc') < 0, 'null should be come before real values');
assert(compareFileNames('', '') === 0, 'empty should be equal');
@ -35,15 +25,6 @@ suite('Comparers', () => {
test('compareFileExtensions', () => {
// Setup Intl
setFileNameComparer(new IdleValue(() => {
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
return {
collator: collator,
collatorIsNumeric: collator.resolvedOptions().numeric
};
}));
assert(compareFileExtensions(null, null) === 0, 'null should be equal');
assert(compareFileExtensions(null, '.abc') < 0, 'null should come before real files');
assert(compareFileExtensions(null, 'abc') < 0, 'null should come before real files without extension');
@ -66,4 +47,4 @@ suite('Comparers', () => {
assert(compareFileExtensions('file2.ext2', 'file1.ext10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order');
assert(compareFileExtensions('file.ext01', 'file.ext1') < 0, 'extensions with equal numbers should be in alphabetical order');
});
});
});

View file

@ -364,4 +364,42 @@ suite('Buffer', () => {
assert.equal(ended, false);
assert.equal(errors.length, 0);
});
test('Performance issue with VSBuffer#slice #76076', function () {
// Buffer#slice creates a view
{
const buff = Buffer.from([10, 20, 30, 40]);
const b2 = buff.slice(1, 3);
assert.equal(buff[1], 20);
assert.equal(b2[0], 20);
buff[1] = 17; // modify buff AND b2
assert.equal(buff[1], 17);
assert.equal(b2[0], 17);
}
// TypedArray#slice creates a copy
{
const unit = new Uint8Array([10, 20, 30, 40]);
const u2 = unit.slice(1, 3);
assert.equal(unit[1], 20);
assert.equal(u2[0], 20);
unit[1] = 17; // modify unit, NOT b2
assert.equal(unit[1], 17);
assert.equal(u2[0], 20);
}
// TypedArray#subarray creates a view
{
const unit = new Uint8Array([10, 20, 30, 40]);
const u2 = unit.subarray(1, 3);
assert.equal(unit[1], 20);
assert.equal(u2[0], 20);
unit[1] = 17; // modify unit AND b2
assert.equal(unit[1], 17);
assert.equal(u2[0], 17);
}
});
});

View file

@ -4,6 +4,8 @@
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="/favicon.ico" />
<!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

View file

@ -48,6 +48,9 @@ import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnosticsService';
import { DiagnosticsChannel } from 'vs/platform/diagnostics/node/diagnosticsIpc';
export interface ISharedProcessConfiguration {
readonly machineId: string;
@ -121,6 +124,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
const instantiationService = new InstantiationService(services);
let telemetryService: ITelemetryService;
instantiationService.invokeFunction(accessor => {
const services = new ServiceCollection();
const environmentService = accessor.get(IEnvironmentService);
@ -141,8 +145,10 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
piiPaths: [appRoot, extensionsPath]
};
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
telemetryService = new TelemetryService(config, configurationService);
services.set(ITelemetryService, telemetryService);
} else {
telemetryService = NullTelemetryService;
services.set(ITelemetryService, NullTelemetryService);
}
server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appInsightsAppender));
@ -150,6 +156,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
const instantiationService2 = instantiationService.createChild(services);
@ -163,6 +170,10 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
const localizationsChannel = new LocalizationsChannel(localizationsService);
server.registerChannel('localizations', localizationsChannel);
const diagnosticsService = accessor.get(IDiagnosticsService);
const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService);
server.registerChannel('diagnostics', diagnosticsChannel);
// clean up deprecated extensions
(extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions();
// update localizations cache

View file

@ -81,6 +81,8 @@ import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFacto
import { VSBuffer } from 'vs/base/common/buffer';
import { statSync } from 'fs';
import { ISignService } from 'vs/platform/sign/common/sign';
import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnosticsService';
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
export class CodeApplication extends Disposable {
@ -407,6 +409,10 @@ export class CodeApplication extends Disposable {
services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv]));
services.set(IWindowsService, new SyncDescriptor(WindowsService, [sharedProcess]));
services.set(ILaunchService, new SyncDescriptor(LaunchService));
const diagnosticsChannel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('diagnostics')));
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, [diagnosticsChannel]));
services.set(IIssueService, new SyncDescriptor(IssueService, [machineId, this.userEnv]));
services.set(IMenubarService, new SyncDescriptor(MenubarService));

View file

@ -33,7 +33,6 @@ import { CodeApplication } from 'vs/code/electron-main/app';
import { localize } from 'vs/nls';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { IDiagnosticsService, DiagnosticsService } from 'vs/platform/diagnostics/electron-main/diagnosticsService';
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
import { IThemeMainService, ThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
@ -41,6 +40,7 @@ import { Client } from 'vs/base/parts/ipc/common/ipc.net';
import { once } from 'vs/base/common/functional';
import { ISignService } from 'vs/platform/sign/common/sign';
import { SignService } from 'vs/platform/sign/node/signService';
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
class ExpectedError extends Error {
readonly isExpected = true;
@ -146,7 +146,6 @@ class CodeMain {
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
services.set(IStateService, new SyncDescriptor(StateService));
services.set(IRequestService, new SyncDescriptor(RequestService));
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
services.set(IThemeMainService, new SyncDescriptor(ThemeMainService));
services.set(ISignService, new SyncDescriptor(SignService));
@ -277,7 +276,13 @@ class CodeMain {
// Process Info
if (environmentService.args.status) {
return instantiationService.invokeFunction(async accessor => {
const diagnostics = await accessor.get(IDiagnosticsService).getDiagnostics(launchClient);
// Create a diagnostic service connected to the existing shared process
const sharedProcessClient = await connect(environmentService.sharedIPCHandle, 'main');
const diagnosticsChannel = sharedProcessClient.getChannel('diagnostics');
const diagnosticsService = new DiagnosticsService(diagnosticsChannel);
const mainProcessInfo = await launchClient.getMainProcessInfo();
const remoteDiagnostics = await launchClient.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
const diagnostics = await diagnosticsService.getDiagnostics(mainProcessInfo, remoteDiagnostics);
console.log(diagnostics);
throw new ExpectedError();

View file

@ -869,16 +869,17 @@ export class CodeWindow extends Disposable implements ICodeWindow {
}
private useNativeFullScreen(): boolean {
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
if (!windowConfig || typeof windowConfig.nativeFullScreen !== 'boolean') {
return true; // default
}
return true;
// const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
// if (!windowConfig || typeof windowConfig.nativeFullScreen !== 'boolean') {
// return true; // default
// }
if (windowConfig.nativeTabs) {
return true; // https://github.com/electron/electron/issues/16142
}
// if (windowConfig.nativeTabs) {
// return true; // https://github.com/electron/electron/issues/16142
// }
return windowConfig.nativeFullScreen !== false;
// return windowConfig.nativeFullScreen !== false;
}
isMinimized(): boolean {

View file

@ -25,7 +25,8 @@ function shouldSpawnCliProcess(argv: ParsedArgs): boolean {
|| !!argv['list-extensions']
|| !!argv['install-extension']
|| !!argv['uninstall-extension']
|| !!argv['locate-extension'];
|| !!argv['locate-extension']
|| !!argv['telemetry'];
}
interface IMainCli {

View file

@ -41,6 +41,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
import { Schemas } from 'vs/base/common/network';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { buildTelemetryMessage } from 'vs/platform/environment/node/argv';
const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id);
@ -94,6 +95,8 @@ export class Main {
const arg = argv['locate-extension'];
const ids: string[] = typeof arg === 'string' ? [arg] : arg;
await this.locateExtension(ids);
} else if (argv['telemetry']) {
console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath));
}
}

View file

@ -451,7 +451,7 @@ export class Minimap extends ViewPart {
private _options: MinimapOptions;
private _lastRenderData: RenderData | null;
private _decorationsChanged: boolean = false;
private _renderDecorations: boolean = false;
private _buffers: MinimapBuffers | null;
constructor(context: ViewContext) {
@ -498,7 +498,7 @@ export class Minimap extends ViewPart {
this._applyLayout();
this._mouseDownListener = dom.addStandardDisposableListener(this._canvas.domNode, 'mousedown', (e) => {
this._mouseDownListener = dom.addStandardDisposableListener(this._domNode.domNode, 'mousedown', (e) => {
e.preventDefault();
const renderMinimap = this._options.renderMinimap;
@ -527,6 +527,7 @@ export class Minimap extends ViewPart {
this._sliderMouseDownListener = dom.addStandardDisposableListener(this._slider.domNode, 'mousedown', (e) => {
e.preventDefault();
e.stopPropagation();
if (e.leftButton && this._lastRenderData) {
const initialMousePosition = e.posy;
@ -650,6 +651,7 @@ export class Minimap extends ViewPart {
return true;
}
public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {
this._renderDecorations = true;
return true;
}
public onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {
@ -669,7 +671,7 @@ export class Minimap extends ViewPart {
}
public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {
this._decorationsChanged = true;
this._renderDecorations = true;
return true;
}
@ -720,9 +722,8 @@ export class Minimap extends ViewPart {
}
private renderDecorations(layout: MinimapLayout) {
const scrollHasChanged = this._lastRenderData && !this._lastRenderData.scrollEquals(layout);
if (scrollHasChanged || this._decorationsChanged) {
this._decorationsChanged = false;
if (this._renderDecorations) {
this._renderDecorations = false;
const decorations = this._context.model.getDecorationsInViewport(new Range(layout.startLineNumber, 1, layout.endLineNumber, this._context.model.getLineMaxColumn(layout.endLineNumber)));
const { renderMinimap, canvasInnerWidth, canvasInnerHeight } = this._options;
@ -737,50 +738,64 @@ export class Minimap extends ViewPart {
const lineHeightRatio = renderMinimap === RenderMinimap.LargeBlocks || renderMinimap === RenderMinimap.SmallBlocks ? 0.5 : 1;
const height = lineHeight * lineHeightRatio;
for (let i = 0; i < decorations.length; i++) {
if (decorations[i].options.minimap) {
this.renderDecoration(canvasContext, decorations[i], layout, height, lineHeight, tabSize, characterWidth);
// Loop over decorations, ignoring those that don't have the minimap property set and rendering those on the same line together
let i = 0;
for (; i < decorations.length; i++) {
if (!decorations[i].options.minimap) {
continue;
}
let decorationsForLine = [decorations[i]];
let currentLine = decorations[i].range.startLineNumber;
let j = i + 1;
while (j < decorations.length && decorations[j].range.startLineNumber === currentLine) {
if (decorations[j].options.minimap) {
decorationsForLine.push(decorations[j]);
}
j += 1;
}
i = j - 1;
this.renderDecorationsForLine(canvasContext, decorationsForLine, layout, currentLine, height, lineHeight, tabSize, characterWidth);
}
}
}
private renderDecoration(canvasContext: CanvasRenderingContext2D,
decoration: ViewModelDecoration,
private renderDecorationsForLine(canvasContext: CanvasRenderingContext2D,
decorations: ViewModelDecoration[],
layout: MinimapLayout,
startLineNumber: number,
height: number,
lineHeight: number,
tabSize: number,
charWidth: number) {
const { startLineNumber, startColumn, endColumn } = decoration.range;
const startIndex = startColumn - 1;
const endIndex = endColumn - 1;
const y = (startLineNumber - layout.startLineNumber) * lineHeight;
// Get the offset of the decoration in the line. Have to read line data to see how much space each character takes.
let x = 0;
let endPosition = 0;
const lineData = this._context.model.getLineContent(startLineNumber);
for (let i = 0; i < endIndex; i++) {
const charCode = lineData.charCodeAt(i);
const lineIndexToXOffset = [0];
for (let i = 1; i < lineData.length + 1; i++) {
const charCode = lineData.charCodeAt(i - 1);
const dx = charCode === CharCode.Tab
? tabSize * charWidth
: strings.isFullWidthCharacter(charCode)
? 2 * charWidth
: charWidth;
if (i < startIndex) {
x += dx;
}
endPosition += dx;
lineIndexToXOffset[i] = lineIndexToXOffset[i - 1] + dx;
}
const width = endPosition - x;
for (let i = 0; i < decorations.length; i++) {
const currentDecoration = decorations[i];
const { startColumn, endColumn } = currentDecoration.range;
const x = lineIndexToXOffset[startColumn - 1];
const width = lineIndexToXOffset[endColumn - 1] - x;
const minimapOptions = <ModelDecorationMinimapOptions>decoration.options.minimap;
this.renderDecoration(canvasContext, <ModelDecorationMinimapOptions>currentDecoration.options.minimap, x, y, width, height);
}
}
private renderDecoration(canvasContext: CanvasRenderingContext2D, minimapOptions: ModelDecorationMinimapOptions, x: number, y: number, width: number, height: number) {
const decorationColor = minimapOptions.getColor(this._context.theme);
canvasContext.fillStyle = decorationColor;

View file

@ -36,7 +36,7 @@ export class Position {
}
/**
* Create a new postion from this position.
* Create a new position from this position.
*
* @param newLineNumber new line number
* @param newColumn new column

View file

@ -611,25 +611,25 @@ export class PieceTreeBase {
let resultLen = 0;
const searcher = new Searcher(searchData.wordSeparators, searchData.regex);
let startPostion = this.nodeAt2(searchRange.startLineNumber, searchRange.startColumn);
if (startPostion === null) {
let startPosition = this.nodeAt2(searchRange.startLineNumber, searchRange.startColumn);
if (startPosition === null) {
return [];
}
let endPosition = this.nodeAt2(searchRange.endLineNumber, searchRange.endColumn);
if (endPosition === null) {
return [];
}
let start = this.positionInBuffer(startPostion.node, startPostion.remainder);
let start = this.positionInBuffer(startPosition.node, startPosition.remainder);
let end = this.positionInBuffer(endPosition.node, endPosition.remainder);
if (startPostion.node === endPosition.node) {
this.findMatchesInNode(startPostion.node, searcher, searchRange.startLineNumber, searchRange.startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result);
if (startPosition.node === endPosition.node) {
this.findMatchesInNode(startPosition.node, searcher, searchRange.startLineNumber, searchRange.startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result);
return result;
}
let startLineNumber = searchRange.startLineNumber;
let currentNode = startPostion.node;
let currentNode = startPosition.node;
while (currentNode !== endPosition.node) {
let lineBreakCnt = this.getLineFeedCnt(currentNode.piece.bufferIndex, start, currentNode.piece.end);
@ -663,9 +663,9 @@ export class PieceTreeBase {
}
startLineNumber++;
startPostion = this.nodeAt2(startLineNumber, 1);
currentNode = startPostion.node;
start = this.positionInBuffer(startPostion.node, startPostion.remainder);
startPosition = this.nodeAt2(startLineNumber, 1);
currentNode = startPosition.node;
start = this.positionInBuffer(startPosition.node, startPosition.remainder);
}
if (startLineNumber === searchRange.endLineNumber) {

View file

@ -25,7 +25,7 @@ export interface ITextResourceConfigurationService {
* Value can be of native type or an object keyed off the section name.
*
* @param resource - Resource for which the configuration has to be fetched.
* @param postion - Position in the resource for which configuration has to be fetched.
* @param position - Position in the resource for which configuration has to be fetched.
* @param section - Section of the configuraion.
*
*/

View file

@ -19,7 +19,7 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { ILocalProgressService } from 'vs/platform/progress/common/progress';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { CodeActionModel, SUPPORTED_CODE_ACTIONS, CodeActionsState } from './codeActionModel';
import { CodeActionAutoApply, CodeActionFilter, CodeActionKind, CodeActionTrigger } from './codeActionTrigger';
import { CodeActionWidget } from './codeActionWidget';
@ -52,7 +52,7 @@ export class QuickFixController extends Disposable implements IEditorContributio
editor: ICodeEditor,
@IMarkerService markerService: IMarkerService,
@IContextKeyService contextKeyService: IContextKeyService,
@ILocalProgressService progressService: ILocalProgressService,
@IEditorProgressService progressService: IEditorProgressService,
@IContextMenuService contextMenuService: IContextMenuService,
@ICommandService private readonly _commandService: ICommandService,
@IKeybindingService private readonly _keybindingService: IKeybindingService,

View file

@ -14,7 +14,7 @@ import { Selection } from 'vs/editor/common/core/selection';
import { CodeActionProviderRegistry } from 'vs/editor/common/modes';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { ILocalProgressService } from 'vs/platform/progress/common/progress';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { getCodeActions, CodeActionSet } from './codeAction';
import { CodeActionTrigger } from './codeActionTrigger';
@ -167,7 +167,7 @@ export class CodeActionModel extends Disposable {
private readonly _editor: ICodeEditor,
private readonly _markerService: IMarkerService,
contextKeyService: IContextKeyService,
private readonly _progressService?: ILocalProgressService
private readonly _progressService?: IEditorProgressService
) {
super();
this._supportedCodeActions = SUPPORTED_CODE_ACTIONS.bindTo(contextKeyService);

View file

@ -91,7 +91,7 @@ export class DragAndDropCommand implements editorCommon.ICommand {
this.selection.endColumn
);
} else {
// The target position is before the selection's end postion. Since the selection doesn't contain the target position, the selection is one-line and target position is before this selection.
// The target position is before the selection's end position. Since the selection doesn't contain the target position, the selection is one-line and target position is before this selection.
this.targetSelection = new Selection(
this.targetPosition.lineNumber - this.selection.endLineNumber + this.selection.startLineNumber,
this.targetPosition.column,

View file

@ -15,20 +15,18 @@ import { Range } from 'vs/editor/common/core/range';
import { SymbolKind, symbolKindToCssClass } from 'vs/editor/common/modes';
import { OutlineElement, OutlineGroup, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
import { localize } from 'vs/nls';
import { IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { OutlineConfigKeys } from 'vs/editor/contrib/documentSymbols/outline';
import { MarkerSeverity } from 'vs/platform/markers/common/markers';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { listErrorForeground, listWarningForeground } from 'vs/platform/theme/common/colorRegistry';
import { IdleValue } from 'vs/base/common/async';
export type OutlineItem = OutlineGroup | OutlineElement;
export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelProvider<OutlineItem> {
constructor(@IKeybindingService private readonly _keybindingService: IKeybindingService) { }
getKeyboardNavigationLabel(element: OutlineItem): { toString(): string; } {
if (element instanceof OutlineGroup) {
return element.provider.displayName || element.id;
@ -36,10 +34,6 @@ export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelP
return element.symbol.name;
}
}
mightProducePrintableCharacter(event: IKeyboardEvent): boolean {
return this._keybindingService.mightProducePrintableCharacter(event);
}
}
@ -215,6 +209,8 @@ export const enum OutlineSortOrder {
export class OutlineItemComparator implements ITreeSorter<OutlineItem> {
private readonly _collator = new IdleValue<Intl.Collator>(() => new Intl.Collator(undefined, { numeric: true }));
constructor(
public type: OutlineSortOrder = OutlineSortOrder.ByPosition
) { }
@ -225,11 +221,11 @@ export class OutlineItemComparator implements ITreeSorter<OutlineItem> {
} else if (a instanceof OutlineElement && b instanceof OutlineElement) {
if (this.type === OutlineSortOrder.ByKind) {
return a.symbol.kind - b.symbol.kind || a.symbol.name.localeCompare(b.symbol.name, undefined, { numeric: true });
return a.symbol.kind - b.symbol.kind || this._collator.getValue().compare(a.symbol.name, b.symbol.name);
} else if (this.type === OutlineSortOrder.ByName) {
return a.symbol.name.localeCompare(b.symbol.name, undefined, { numeric: true }) || Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range);
return this._collator.getValue().compare(a.symbol.name, b.symbol.name) || Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range);
} else if (this.type === OutlineSortOrder.ByPosition) {
return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) || a.symbol.name.localeCompare(b.symbol.name, undefined, { numeric: true });
return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) || this._collator.getValue().compare(a.symbol.name, b.symbol.name);
}
}
return 0;

View file

@ -78,7 +78,7 @@
background-image: url('images/close-dark.svg');
}
monaco-workbench .simple-find-part .button.disabled {
.monaco-workbench .simple-find-part .button.disabled {
opacity: 0.3;
cursor: default;
}

View file

@ -33,6 +33,9 @@ export abstract class SimpleFindWidget extends Widget {
private readonly _focusTracker: dom.IFocusTracker;
private readonly _findInputFocusTracker: dom.IFocusTracker;
private readonly _updateHistoryDelayer: Delayer<void>;
private prevBtn: SimpleButton;
private nextBtn: SimpleButton;
private foundMatch: boolean;
constructor(
@IContextViewService private readonly _contextViewService: IContextViewService,
@ -54,6 +57,8 @@ export abstract class SimpleFindWidget extends Widget {
new RegExp(value);
return null;
} catch (e) {
this.foundMatch = false;
this._updateButtons();
return { content: e.message };
}
}
@ -63,7 +68,8 @@ export abstract class SimpleFindWidget extends Widget {
this._updateHistoryDelayer = new Delayer<void>(500);
this.oninput(this._findInput.domNode, (e) => {
this.onInputChanged();
this.foundMatch = this.onInputChanged();
this._updateButtons();
this._delayedUpdateHistory();
});
@ -99,7 +105,7 @@ export abstract class SimpleFindWidget extends Widget {
}
}));
const prevBtn = this._register(new SimpleButton({
this.prevBtn = this._register(new SimpleButton({
label: NLS_PREVIOUS_MATCH_BTN_LABEL,
className: 'previous',
onTrigger: () => {
@ -107,7 +113,7 @@ export abstract class SimpleFindWidget extends Widget {
}
}));
const nextBtn = this._register(new SimpleButton({
this.nextBtn = this._register(new SimpleButton({
label: NLS_NEXT_MATCH_BTN_LABEL,
className: 'next',
onTrigger: () => {
@ -126,8 +132,8 @@ export abstract class SimpleFindWidget extends Widget {
this._innerDomNode = document.createElement('div');
this._innerDomNode.classList.add('simple-find-part');
this._innerDomNode.appendChild(this._findInput.domNode);
this._innerDomNode.appendChild(prevBtn.domNode);
this._innerDomNode.appendChild(nextBtn.domNode);
this._innerDomNode.appendChild(this.prevBtn.domNode);
this._innerDomNode.appendChild(this.nextBtn.domNode);
this._innerDomNode.appendChild(closeBtn.domNode);
// _domNode wraps _innerDomNode, ensuring that
@ -156,7 +162,7 @@ export abstract class SimpleFindWidget extends Widget {
}));
}
protected abstract onInputChanged(): void;
protected abstract onInputChanged(): boolean;
protected abstract find(previous: boolean): void;
protected abstract onFocusTrackerFocus(): void;
protected abstract onFocusTrackerBlur(): void;
@ -213,6 +219,7 @@ export abstract class SimpleFindWidget extends Widget {
}
this._isVisible = true;
this._updateButtons();
setTimeout(() => {
dom.addClass(this._innerDomNode, 'visible');
@ -243,6 +250,7 @@ export abstract class SimpleFindWidget extends Widget {
// Need to delay toggling visibility until after Transition, then visibility hidden - removes from tabIndex list
setTimeout(() => {
this._isVisible = false;
this._updateButtons();
dom.removeClass(this._innerDomNode, 'visible');
}, 200);
}
@ -267,6 +275,12 @@ export abstract class SimpleFindWidget extends Widget {
protected _getCaseSensitiveValue(): boolean {
return this._findInput.getCaseSensitive();
}
private _updateButtons() {
let hasInput = this.inputValue.length > 0;
this.prevBtn.setEnabled(this._isVisible && hasInput && this.foundMatch);
this.nextBtn.setEnabled(this._isVisible && hasInput && this.foundMatch);
}
}
// theming

View file

@ -25,7 +25,7 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ILocalProgressService } from 'vs/platform/progress/common/progress';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition } from './goToDefinition';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState';
@ -58,7 +58,7 @@ export class DefinitionAction extends EditorAction {
}
const notificationService = accessor.get(INotificationService);
const editorService = accessor.get(ICodeEditorService);
const progressService = accessor.get(ILocalProgressService);
const progressService = accessor.get(IEditorProgressService);
const symbolNavService = accessor.get(ISymbolNavigationService);
const model = editor.getModel();

View file

@ -27,26 +27,26 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic
const HOVER_MESSAGE_GENERAL_META = new MarkdownString().appendText(
platform.isMacintosh
? nls.localize('links.navigate.mac', "Cmd + click to follow link")
: nls.localize('links.navigate', "Ctrl + click to follow link")
? nls.localize('links.navigate.mac', "Follow link (cmd + click)")
: nls.localize('links.navigate', "Follow link (ctrl + click)")
);
const HOVER_MESSAGE_COMMAND_META = new MarkdownString().appendText(
platform.isMacintosh
? nls.localize('links.command.mac', "Cmd + click to execute command")
: nls.localize('links.command', "Ctrl + click to execute command")
? nls.localize('links.command.mac', "Execute command (cmd + click)")
: nls.localize('links.command', "Execute command (ctrl + click)")
);
const HOVER_MESSAGE_GENERAL_ALT = new MarkdownString().appendText(
platform.isMacintosh
? nls.localize('links.navigate.al.mac', "Option + click to follow link")
: nls.localize('links.navigate.al', "Alt + click to follow link")
? nls.localize('links.navigate.al.mac', "Follow link (option + click)")
: nls.localize('links.navigate.al', "Follow link (alt + click)")
);
const HOVER_MESSAGE_COMMAND_ALT = new MarkdownString().appendText(
platform.isMacintosh
? nls.localize('links.command.al.mac', "Option + click to execute command")
: nls.localize('links.command.al', "Alt + click to execute command")
? nls.localize('links.command.al.mac', "Execute command (option + click)")
: nls.localize('links.command.al', "Execute command (alt + click)")
);
const decoration = {
@ -116,11 +116,11 @@ class LinkOccurrence {
const message = new MarkdownString().appendText(
platform.isMacintosh
? useMetaKey
? nls.localize('links.custom.mac', "Cmd + click to {0}", link.tooltip)
: nls.localize('links.custom.mac.al', "Option + click to {0}", link.tooltip)
? nls.localize('links.custom.mac', "{0} (cmd + click)", link.tooltip)
: nls.localize('links.custom.mac.al', "{0} (option + click)", link.tooltip)
: useMetaKey
? nls.localize('links.custom', "Ctrl + click to {0}", link.tooltip)
: nls.localize('links.custom.al', "Alt + click to {0}", link.tooltip)
? nls.localize('links.custom', "{0} (ctrl + click)", link.tooltip)
: nls.localize('links.custom.al', "{0} (alt + click)", link.tooltip)
);
options.hoverMessage = message;
}

View file

@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import { illegalArgument, onUnexpectedError } from 'vs/base/common/errors';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ILocalProgressService } from 'vs/platform/progress/common/progress';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, EditorCommand, registerEditorCommand, registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
@ -114,7 +114,7 @@ class RenameController extends Disposable implements IEditorContribution {
private readonly editor: ICodeEditor,
@INotificationService private readonly _notificationService: INotificationService,
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@ILocalProgressService private readonly _progressService: ILocalProgressService,
@IEditorProgressService private readonly _progressService: IEditorProgressService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IThemeService private readonly _themeService: IThemeService,
) {

View file

@ -38,7 +38,7 @@ import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKe
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
import { ILabelService, ResourceLabelFormatter } from 'vs/platform/label/common/label';
import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions } from 'vs/platform/notification/common/notification';
import { IProgressRunner, ILocalProgressService } from 'vs/platform/progress/common/progress';
import { IProgressRunner, IEditorProgressService } from 'vs/platform/progress/common/progress';
import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
@ -137,7 +137,7 @@ export class SimpleEditorModelResolverService implements ITextModelService {
}
}
export class SimpleLocalProgressService implements ILocalProgressService {
export class SimpleEditorProgressService implements IEditorProgressService {
_serviceBrand: any;
private static NULL_PROGRESS_RUNNER: IProgressRunner = {
@ -149,7 +149,7 @@ export class SimpleLocalProgressService implements ILocalProgressService {
show(infinite: true, delay?: number): IProgressRunner;
show(total: number, delay?: number): IProgressRunner;
show(): IProgressRunner {
return SimpleLocalProgressService.NULL_PROGRESS_RUNNER;
return SimpleEditorProgressService.NULL_PROGRESS_RUNNER;
}
showWhile(promise: Promise<any>, delay?: number): Promise<void> {

View file

@ -13,7 +13,7 @@ import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleLocalProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService, SimpleLayoutService } from 'vs/editor/standalone/browser/simpleServices';
import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleEditorProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService, SimpleLayoutService } from 'vs/editor/standalone/browser/simpleServices';
import { StandaloneCodeEditorServiceImpl } from 'vs/editor/standalone/browser/standaloneCodeServiceImpl';
import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standaloneThemeServiceImpl';
import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';
@ -36,7 +36,7 @@ import { ILogService, NullLogService } from 'vs/platform/log/common/log';
import { MarkerService } from 'vs/platform/markers/common/markerService';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ILocalProgressService } from 'vs/platform/progress/common/progress';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
@ -44,11 +44,10 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
import { MenuService } from 'vs/platform/actions/common/menuService';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl';
import { ISuggestMemoryService, SuggestMemoryService } from 'vs/editor/contrib/suggest/suggestMemory';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { ICodeLensCache, CodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache';
import { getServices } from 'vs/platform/instantiation/common/extensions';
export interface IEditorOverrideServices {
[index: string]: any;
@ -100,6 +99,11 @@ export module StaticServices {
// Create a fresh service collection
let result = new ServiceCollection();
// make sure to add all services that use `registerSingleton`
for (const { id, descriptor } of getServices()) {
result.set(id, descriptor);
}
// Initialize the service collection with the overrides
for (let serviceId in overrides) {
if (overrides.hasOwnProperty(serviceId)) {
@ -150,17 +154,13 @@ export module StaticServices {
export const codeEditorService = define(ICodeEditorService, (o) => new StandaloneCodeEditorServiceImpl(standaloneThemeService.get(o)));
export const localProgressService = define(ILocalProgressService, () => new SimpleLocalProgressService());
export const editorProgressService = define(IEditorProgressService, () => new SimpleEditorProgressService());
export const storageService = define(IStorageService, () => new InMemoryStorageService());
export const logService = define(ILogService, () => new NullLogService());
export const editorWorkerService = define(IEditorWorkerService, (o) => new EditorWorkerServiceImpl(modelService.get(o), resourceConfigurationService.get(o), logService.get(o)));
export const suggestMemoryService = define(ISuggestMemoryService, (o) => new SuggestMemoryService(storageService.get(o), configurationService.get(o)));
export const codeLensCacheService = define(ICodeLensCache, (o) => new CodeLensCache(storageService.get(o)));
}
export class DynamicStandaloneServices extends Disposable {

2
src/vs/monaco.d.ts vendored
View file

@ -453,7 +453,7 @@ declare namespace monaco {
readonly column: number;
constructor(lineNumber: number, column: number);
/**
* Create a new postion from this position.
* Create a new position from this position.
*
* @param newLineNumber new line number
* @param newColumn new column

View file

@ -5,6 +5,9 @@
import { UriComponents } from 'vs/base/common/uri';
import { ProcessItem } from 'vs/base/common/processes';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IMainProcessInfo } from 'vs/platform/launch/common/launchService';
import { IWorkspace } from 'vs/platform/workspace/common/workspace';
export interface IMachineInfo {
os: string;
@ -51,6 +54,24 @@ export interface WorkspaceStats {
configFiles: WorkspaceStatItem[];
fileCount: number;
maxFilesReached: boolean;
launchConfigFiles: WorkspaceStatItem[];
}
export interface PerformanceInfo {
processInfo?: string;
workspaceInfo?: string;
}
export const ID = 'diagnosticsService';
export const IDiagnosticsService = createDecorator<IDiagnosticsService>(ID);
export interface IDiagnosticsService {
_serviceBrand: any;
getPerformanceInfo(mainProcessInfo: IMainProcessInfo, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<PerformanceInfo>;
getSystemInfo(mainProcessInfo: IMainProcessInfo, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<SystemInfo>;
getDiagnostics(mainProcessInfo: IMainProcessInfo, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<string>;
reportWorkspaceStats(workspace: IWorkspace): Promise<void>;
}
export function isRemoteDiagnosticError(x: any): x is IRemoteDiagnosticError {

View file

@ -1,389 +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 { IMainProcessInfo, ILaunchService } from 'vs/platform/launch/electron-main/launchService';
import { listProcesses } from 'vs/base/node/ps';
import product from 'vs/platform/product/node/product';
import pkg from 'vs/platform/product/node/package';
import * as osLib from 'os';
import { virtualMachineHint } from 'vs/base/node/id';
import { repeat, pad } from 'vs/base/common/strings';
import { isWindows } from 'vs/base/common/platform';
import { app } from 'electron';
import { basename } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IMachineInfo, WorkspaceStats, SystemInfo, IRemoteDiagnosticInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
import { collectWorkspaceStats, getMachineInfo } from 'vs/platform/diagnostics/node/diagnosticsService';
import { ProcessItem } from 'vs/base/common/processes';
export const ID = 'diagnosticsService';
export const IDiagnosticsService = createDecorator<IDiagnosticsService>(ID);
export interface IDiagnosticsService {
_serviceBrand: any;
getPerformanceInfo(launchService: ILaunchService): Promise<PerformanceInfo>;
getSystemInfo(launchService: ILaunchService): Promise<SystemInfo>;
getDiagnostics(launchService: ILaunchService): Promise<string>;
}
export interface VersionInfo {
vscodeVersion: string;
os: string;
}
export interface ProcessInfo {
cpu: number;
memory: number;
pid: number;
name: string;
}
export interface PerformanceInfo {
processInfo?: string;
workspaceInfo?: string;
}
export class DiagnosticsService implements IDiagnosticsService {
_serviceBrand: any;
private formatMachineInfo(info: IMachineInfo): string {
const output: string[] = [];
output.push(`OS Version: ${info.os}`);
output.push(`CPUs: ${info.cpus}`);
output.push(`Memory (System): ${info.memory}`);
output.push(`VM: ${info.vmHint}`);
return output.join('\n');
}
private formatEnvironment(info: IMainProcessInfo): string {
const MB = 1024 * 1024;
const GB = 1024 * MB;
const output: string[] = [];
output.push(`Version: ${pkg.name} ${pkg.version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})`);
output.push(`OS Version: ${osLib.type()} ${osLib.arch()} ${osLib.release()}`);
const cpus = osLib.cpus();
if (cpus && cpus.length > 0) {
output.push(`CPUs: ${cpus[0].model} (${cpus.length} x ${cpus[0].speed})`);
}
output.push(`Memory (System): ${(osLib.totalmem() / GB).toFixed(2)}GB (${(osLib.freemem() / GB).toFixed(2)}GB free)`);
if (!isWindows) {
output.push(`Load (avg): ${osLib.loadavg().map(l => Math.round(l)).join(', ')}`); // only provided on Linux/macOS
}
output.push(`VM: ${Math.round((virtualMachineHint.value() * 100))}%`);
output.push(`Screen Reader: ${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`);
output.push(`Process Argv: ${info.mainArguments.join(' ')}`);
output.push(`GPU Status: ${this.expandGPUFeatures()}`);
return output.join('\n');
}
async getPerformanceInfo(launchService: ILaunchService): Promise<PerformanceInfo> {
const info = await launchService.getMainProcessInfo();
return Promise.all<ProcessItem, string>([listProcesses(info.mainPID), this.formatWorkspaceMetadata(info)]).then(async result => {
let [rootProcess, workspaceInfo] = result;
let processInfo = this.formatProcessList(info, rootProcess);
try {
const remoteData = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
remoteData.forEach(diagnostics => {
if (isRemoteDiagnosticError(diagnostics)) {
processInfo += `\n${diagnostics.errorMessage}`;
workspaceInfo += `\n${diagnostics.errorMessage}`;
} else {
processInfo += `\n\nRemote: ${diagnostics.hostName}`;
if (diagnostics.processes) {
processInfo += `\n${this.formatProcessList(info, diagnostics.processes)}`;
}
if (diagnostics.workspaceMetadata) {
workspaceInfo += `\n| Remote: ${diagnostics.hostName}`;
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
const metadata = diagnostics.workspaceMetadata[folder];
let countMessage = `${metadata.fileCount} files`;
if (metadata.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
workspaceInfo += `| Folder (${folder}): ${countMessage}`;
workspaceInfo += this.formatWorkspaceStats(metadata);
}
}
}
});
} catch (e) {
processInfo += `\nFetching remote data failed: ${e}`;
workspaceInfo += `\nFetching remote data failed: ${e}`;
}
return {
processInfo,
workspaceInfo
};
});
}
async getSystemInfo(launchService: ILaunchService): Promise<SystemInfo> {
const info = await launchService.getMainProcessInfo();
const { memory, vmHint, os, cpus } = getMachineInfo();
const systemInfo: SystemInfo = {
os,
memory,
cpus,
vmHint,
processArgs: `${info.mainArguments.join(' ')}`,
gpuStatus: app.getGPUFeatureStatus(),
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`,
remoteData: (await launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })).filter((x): x is IRemoteDiagnosticInfo => !(x instanceof Error))
};
if (!isWindows) {
systemInfo.load = `${osLib.loadavg().map(l => Math.round(l)).join(', ')}`;
}
return Promise.resolve(systemInfo);
}
async getDiagnostics(launchService: ILaunchService): Promise<string> {
const output: string[] = [];
const info = await launchService.getMainProcessInfo();
return listProcesses(info.mainPID).then(async rootProcess => {
// Environment Info
output.push('');
output.push(this.formatEnvironment(info));
// Process List
output.push('');
output.push(this.formatProcessList(info, rootProcess));
// Workspace Stats
if (info.windows.some(window => window.folderURIs && window.folderURIs.length > 0 && !window.remoteAuthority)) {
output.push('');
output.push('Workspace Stats: ');
output.push(await this.formatWorkspaceMetadata(info));
}
try {
const data = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
data.forEach(diagnostics => {
if (isRemoteDiagnosticError(diagnostics)) {
output.push(`\n${diagnostics.errorMessage}`);
} else {
output.push('\n\n');
output.push(`Remote: ${diagnostics.hostName}`);
output.push(this.formatMachineInfo(diagnostics.machineInfo));
if (diagnostics.processes) {
output.push(this.formatProcessList(info, diagnostics.processes));
}
if (diagnostics.workspaceMetadata) {
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
const metadata = diagnostics.workspaceMetadata[folder];
let countMessage = `${metadata.fileCount} files`;
if (metadata.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
output.push(`Folder (${folder}): ${countMessage}`);
output.push(this.formatWorkspaceStats(metadata));
}
}
}
});
} catch (e) {
output.push('\n\n');
output.push(`Fetching status information from remotes failed: ${e.message}`);
}
output.push('');
output.push('');
return output.join('\n');
});
}
private formatWorkspaceStats(workspaceStats: WorkspaceStats): string {
const output: string[] = [];
const lineLength = 60;
let col = 0;
const appendAndWrap = (name: string, count: number) => {
const item = ` ${name}(${count})`;
if (col + item.length > lineLength) {
output.push(line);
line = '| ';
col = line.length;
}
else {
col += item.length;
}
line += item;
};
// File Types
let line = '| File types:';
const maxShown = 10;
let max = workspaceStats.fileTypes.length > maxShown ? maxShown : workspaceStats.fileTypes.length;
for (let i = 0; i < max; i++) {
const item = workspaceStats.fileTypes[i];
appendAndWrap(item.name, item.count);
}
output.push(line);
// Conf Files
if (workspaceStats.configFiles.length >= 0) {
line = '| Conf files:';
col = 0;
workspaceStats.configFiles.forEach((item) => {
appendAndWrap(item.name, item.count);
});
output.push(line);
}
// if (workspaceStats.launchConfigFiles.length > 0) {
// let line = '| Launch Configs:';
// workspaceStats.launchConfigFiles.forEach(each => {
// const item = each.count > 1 ? ` ${each.name}(${each.count})` : ` ${each.name}`;
// line += item;
// });
// output.push(line);
// }
return output.join('\n');
}
private expandGPUFeatures(): string {
const gpuFeatures = app.getGPUFeatureStatus();
const longestFeatureName = Math.max(...Object.keys(gpuFeatures).map(feature => feature.length));
// Make columns aligned by adding spaces after feature name
return Object.keys(gpuFeatures).map(feature => `${feature}: ${repeat(' ', longestFeatureName - feature.length)} ${gpuFeatures[feature]}`).join('\n ');
}
private formatWorkspaceMetadata(info: IMainProcessInfo): Promise<string> {
const output: string[] = [];
const workspaceStatPromises: Promise<void>[] = [];
info.windows.forEach(window => {
if (window.folderURIs.length === 0 || !!window.remoteAuthority) {
return;
}
output.push(`| Window (${window.title})`);
window.folderURIs.forEach(uriComponents => {
const folderUri = URI.revive(uriComponents);
if (folderUri.scheme === 'file') {
const folder = folderUri.fsPath;
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(stats => {
let countMessage = `${stats.fileCount} files`;
if (stats.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
output.push(`| Folder (${basename(folder)}): ${countMessage}`);
output.push(this.formatWorkspaceStats(stats));
}).catch(error => {
output.push(`| Error: Unable to collect workspace stats for folder ${folder} (${error.toString()})`);
}));
} else {
output.push(`| Folder (${folderUri.toString()}): Workspace stats not available.`);
}
});
});
return Promise.all(workspaceStatPromises)
.then(_ => output.join('\n'))
.catch(e => `Unable to collect workspace stats: ${e}`);
}
private formatProcessList(info: IMainProcessInfo, rootProcess: ProcessItem): string {
const mapPidToWindowTitle = new Map<number, string>();
info.windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
const output: string[] = [];
output.push('CPU %\tMem MB\t PID\tProcess');
if (rootProcess) {
this.formatProcessItem(info.mainPID, mapPidToWindowTitle, output, rootProcess, 0);
}
return output.join('\n');
}
private formatProcessItem(mainPid: number, mapPidToWindowTitle: Map<number, string>, output: string[], item: ProcessItem, indent: number): void {
const isRoot = (indent === 0);
const MB = 1024 * 1024;
// Format name with indent
let name: string;
if (isRoot) {
name = item.pid === mainPid ? `${product.applicationName} main` : 'remote agent';
} else {
name = `${repeat(' ', indent)} ${item.name}`;
if (item.name === 'window') {
name = `${name} (${mapPidToWindowTitle.get(item.pid)})`;
}
}
const memory = process.platform === 'win32' ? item.mem : (osLib.totalmem() * (item.mem / 100));
output.push(`${pad(Number(item.load.toFixed(0)), 5, ' ')}\t${pad(Number((memory / MB).toFixed(0)), 6, ' ')}\t${pad(Number((item.pid).toFixed(0)), 6, ' ')}\t${name}`);
// Recurse into children if any
if (Array.isArray(item.children)) {
item.children.forEach(child => this.formatProcessItem(mainPid, mapPidToWindowTitle, output, child, indent + 1));
}
}
}
// function collectLaunchConfigs(folder: string): Promise<WorkspaceStatItem[]> {
// const launchConfigs = new Map<string, number>();
// const launchConfig = join(folder, '.vscode', 'launch.json');
// return new Promise((resolve, reject) => {
// exists(launchConfig, (doesExist) => {
// if (doesExist) {
// readFile(launchConfig, (err, contents) => {
// if (err) {
// return resolve([]);
// }
// const errors: ParseError[] = [];
// const json = parse(contents.toString(), errors);
// if (errors.length) {
// output.push(`Unable to parse ${launchConfig}`);
// return resolve([]);
// }
// if (json['configurations']) {
// for (const each of json['configurations']) {
// const type = each['type'];
// if (type) {
// if (launchConfigs.has(type)) {
// launchConfigs.set(type, launchConfigs.get(type)! + 1);
// } else {
// launchConfigs.set(type, 1);
// }
// }
// }
// }
// return resolve(asSortedItems(launchConfigs));
// });
// } else {
// return resolve([]);
// }
// });
// });
// }

View file

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IDiagnosticsService, IRemoteDiagnosticInfo, IRemoteDiagnosticError, SystemInfo, PerformanceInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
import { Event } from 'vs/base/common/event';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IMainProcessInfo } from 'vs/platform/launch/common/launchService';
import { IWorkspace } from 'vs/platform/workspace/common/workspace';
export class DiagnosticsChannel implements IServerChannel {
constructor(private service: IDiagnosticsService) { }
listen(context: any, event: string): Event<any> {
throw new Error('Invalid listen');
}
call(context: any, command: string, args?: any): Promise<any> {
switch (command) {
case 'getDiagnostics':
return this.service.getDiagnostics(args[0], args[1]);
case 'getSystemInfo':
return this.service.getSystemInfo(args[0], args[1]);
case 'getPerformanceInfo':
return this.service.getPerformanceInfo(args[0], args[1]);
case 'reportWorkspaceStats':
return this.service.reportWorkspaceStats(args);
}
throw new Error('Invalid call');
}
}
export class DiagnosticsService implements IDiagnosticsService {
_serviceBrand: ServiceIdentifier<any>;
constructor(private channel: IChannel) { }
public getDiagnostics(mainProcessInfo: IMainProcessInfo, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<string> {
return this.channel.call('getDiagnostics', [mainProcessInfo, remoteInfo]);
}
public getSystemInfo(mainProcessInfo: IMainProcessInfo, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<SystemInfo> {
return this.channel.call('getSystemInfo', [mainProcessInfo, remoteInfo]);
}
public getPerformanceInfo(mainProcessInfo: IMainProcessInfo, remoteInfo: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<PerformanceInfo> {
return this.channel.call('getPerformanceInfo', [mainProcessInfo, remoteInfo]);
}
public reportWorkspaceStats(workspace: IWorkspace): Promise<void> {
return this.channel.call('reportWorkspaceStats', workspace);
}
}

View file

@ -2,28 +2,33 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as os from 'os';
import * as osLib from 'os';
import { virtualMachineHint } from 'vs/base/node/id';
import { IMachineInfo, WorkspaceStats, WorkspaceStatItem } from 'vs/platform/diagnostics/common/diagnosticsService';
import { readdir, stat } from 'fs';
import { join } from 'vs/base/common/path';
import { IMachineInfo, WorkspaceStats, WorkspaceStatItem, IDiagnosticsService, PerformanceInfo, SystemInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
import { readdir, stat, exists, readFile } from 'fs';
import { join, basename } from 'vs/base/common/path';
import { parse, ParseError } from 'vs/base/common/json';
import { listProcesses } from 'vs/base/node/ps';
import product from 'vs/platform/product/node/product';
import pkg from 'vs/platform/product/node/package';
import { repeat, pad } from 'vs/base/common/strings';
import { isWindows } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { ProcessItem } from 'vs/base/common/processes';
import { IMainProcessInfo } from 'vs/platform/launch/common/launchService';
import { IWorkspace } from 'vs/platform/workspace/common/workspace';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export function getMachineInfo(): IMachineInfo {
const MB = 1024 * 1024;
const GB = 1024 * MB;
export interface VersionInfo {
vscodeVersion: string;
os: string;
}
const machineInfo: IMachineInfo = {
os: `${os.type()} ${os.arch()} ${os.release()}`,
memory: `${(os.totalmem() / GB).toFixed(2)}GB (${(os.freemem() / GB).toFixed(2)}GB free)`,
vmHint: `${Math.round((virtualMachineHint.value() * 100))}%`,
};
const cpus = os.cpus();
if (cpus && cpus.length > 0) {
machineInfo.cpus = `${cpus[0].model} (${cpus.length} x ${cpus[0].speed})`;
}
return machineInfo;
export interface ProcessInfo {
cpu: number;
memory: number;
pid: number;
name: string;
}
export function collectWorkspaceStats(folder: string, filter: string[]): Promise<WorkspaceStats> {
@ -145,16 +150,14 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Promise
walk(folder, filter, token, async (files) => {
files.forEach(acceptFile);
// TODO@rachel commented out due to severe performance issues
// see https://github.com/Microsoft/vscode/issues/70563
// const launchConfigs = await collectLaunchConfigs(folder);
const launchConfigs = await collectLaunchConfigs(folder);
resolve({
configFiles: asSortedItems(configFiles),
fileTypes: asSortedItems(fileTypes),
fileCount: token.count,
maxFilesReached: token.maxReached,
// launchConfigFiles: launchConfigs
launchConfigFiles: launchConfigs
});
});
});
@ -164,4 +167,375 @@ function asSortedItems(map: Map<string, number>): WorkspaceStatItem[] {
const a: WorkspaceStatItem[] = [];
map.forEach((value, index) => a.push({ name: index, count: value }));
return a.sort((a, b) => b.count - a.count);
}
export function getMachineInfo(): IMachineInfo {
const MB = 1024 * 1024;
const GB = 1024 * MB;
const machineInfo: IMachineInfo = {
os: `${osLib.type()} ${osLib.arch()} ${osLib.release()}`,
memory: `${(osLib.totalmem() / GB).toFixed(2)}GB (${(osLib.freemem() / GB).toFixed(2)}GB free)`,
vmHint: `${Math.round((virtualMachineHint.value() * 100))}%`,
};
const cpus = osLib.cpus();
if (cpus && cpus.length > 0) {
machineInfo.cpus = `${cpus[0].model} (${cpus.length} x ${cpus[0].speed})`;
}
return machineInfo;
}
export function collectLaunchConfigs(folder: string): Promise<WorkspaceStatItem[]> {
let launchConfigs = new Map<string, number>();
let launchConfig = join(folder, '.vscode', 'launch.json');
return new Promise((resolve, reject) => {
exists(launchConfig, (doesExist) => {
if (doesExist) {
readFile(launchConfig, (err, contents) => {
if (err) {
return resolve([]);
}
const errors: ParseError[] = [];
const json = parse(contents.toString(), errors);
if (errors.length) {
console.log(`Unable to parse ${launchConfig}`);
return resolve([]);
}
if (json['configurations']) {
for (const each of json['configurations']) {
const type = each['type'];
if (type) {
if (launchConfigs.has(type)) {
launchConfigs.set(type, launchConfigs.get(type)! + 1);
} else {
launchConfigs.set(type, 1);
}
}
}
}
return resolve(asSortedItems(launchConfigs));
});
} else {
return resolve([]);
}
});
});
}
export class DiagnosticsService implements IDiagnosticsService {
_serviceBrand: any;
constructor(@ITelemetryService private readonly telemetryService: ITelemetryService) { }
private formatMachineInfo(info: IMachineInfo): string {
const output: string[] = [];
output.push(`OS Version: ${info.os}`);
output.push(`CPUs: ${info.cpus}`);
output.push(`Memory (System): ${info.memory}`);
output.push(`VM: ${info.vmHint}`);
return output.join('\n');
}
private formatEnvironment(info: IMainProcessInfo): string {
const MB = 1024 * 1024;
const GB = 1024 * MB;
const output: string[] = [];
output.push(`Version: ${pkg.name} ${pkg.version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})`);
output.push(`OS Version: ${osLib.type()} ${osLib.arch()} ${osLib.release()}`);
const cpus = osLib.cpus();
if (cpus && cpus.length > 0) {
output.push(`CPUs: ${cpus[0].model} (${cpus.length} x ${cpus[0].speed})`);
}
output.push(`Memory (System): ${(osLib.totalmem() / GB).toFixed(2)}GB (${(osLib.freemem() / GB).toFixed(2)}GB free)`);
if (!isWindows) {
output.push(`Load (avg): ${osLib.loadavg().map(l => Math.round(l)).join(', ')}`); // only provided on Linux/macOS
}
output.push(`VM: ${Math.round((virtualMachineHint.value() * 100))}%`);
output.push(`Screen Reader: ${info.screenReader ? 'yes' : 'no'}`);
output.push(`Process Argv: ${info.mainArguments.join(' ')}`);
output.push(`GPU Status: ${this.expandGPUFeatures(info.gpuFeatureStatus)}`);
return output.join('\n');
}
public async getPerformanceInfo(info: IMainProcessInfo, remoteData: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<PerformanceInfo> {
return Promise.all<ProcessItem, string>([listProcesses(info.mainPID), this.formatWorkspaceMetadata(info)]).then(async result => {
let [rootProcess, workspaceInfo] = result;
let processInfo = this.formatProcessList(info, rootProcess);
remoteData.forEach(diagnostics => {
if (isRemoteDiagnosticError(diagnostics)) {
processInfo += `\n${diagnostics.errorMessage}`;
workspaceInfo += `\n${diagnostics.errorMessage}`;
} else {
processInfo += `\n\nRemote: ${diagnostics.hostName}`;
if (diagnostics.processes) {
processInfo += `\n${this.formatProcessList(info, diagnostics.processes)}`;
}
if (diagnostics.workspaceMetadata) {
workspaceInfo += `\n| Remote: ${diagnostics.hostName}`;
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
const metadata = diagnostics.workspaceMetadata[folder];
let countMessage = `${metadata.fileCount} files`;
if (metadata.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
workspaceInfo += `| Folder (${folder}): ${countMessage}`;
workspaceInfo += this.formatWorkspaceStats(metadata);
}
}
}
});
return {
processInfo,
workspaceInfo
};
});
}
public async getSystemInfo(info: IMainProcessInfo, remoteData: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<SystemInfo> {
const { memory, vmHint, os, cpus } = getMachineInfo();
const systemInfo: SystemInfo = {
os,
memory,
cpus,
vmHint,
processArgs: `${info.mainArguments.join(' ')}`,
gpuStatus: info.gpuFeatureStatus,
screenReader: `${info.screenReader ? 'yes' : 'no'}`,
remoteData
};
if (!isWindows) {
systemInfo.load = `${osLib.loadavg().map(l => Math.round(l)).join(', ')}`;
}
return Promise.resolve(systemInfo);
}
public async getDiagnostics(info: IMainProcessInfo, remoteDiagnostics: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]): Promise<string> {
const output: string[] = [];
return listProcesses(info.mainPID).then(async rootProcess => {
// Environment Info
output.push('');
output.push(this.formatEnvironment(info));
// Process List
output.push('');
output.push(this.formatProcessList(info, rootProcess));
// Workspace Stats
if (info.windows.some(window => window.folderURIs && window.folderURIs.length > 0 && !window.remoteAuthority)) {
output.push('');
output.push('Workspace Stats: ');
output.push(await this.formatWorkspaceMetadata(info));
}
remoteDiagnostics.forEach(diagnostics => {
if (isRemoteDiagnosticError(diagnostics)) {
output.push(`\n${diagnostics.errorMessage}`);
} else {
output.push('\n\n');
output.push(`Remote: ${diagnostics.hostName}`);
output.push(this.formatMachineInfo(diagnostics.machineInfo));
if (diagnostics.processes) {
output.push(this.formatProcessList(info, diagnostics.processes));
}
if (diagnostics.workspaceMetadata) {
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
const metadata = diagnostics.workspaceMetadata[folder];
let countMessage = `${metadata.fileCount} files`;
if (metadata.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
output.push(`Folder (${folder}): ${countMessage}`);
output.push(this.formatWorkspaceStats(metadata));
}
}
}
});
output.push('');
output.push('');
return output.join('\n');
});
}
private formatWorkspaceStats(workspaceStats: WorkspaceStats): string {
const output: string[] = [];
const lineLength = 60;
let col = 0;
const appendAndWrap = (name: string, count: number) => {
const item = ` ${name}(${count})`;
if (col + item.length > lineLength) {
output.push(line);
line = '| ';
col = line.length;
}
else {
col += item.length;
}
line += item;
};
// File Types
let line = '| File types:';
const maxShown = 10;
let max = workspaceStats.fileTypes.length > maxShown ? maxShown : workspaceStats.fileTypes.length;
for (let i = 0; i < max; i++) {
const item = workspaceStats.fileTypes[i];
appendAndWrap(item.name, item.count);
}
output.push(line);
// Conf Files
if (workspaceStats.configFiles.length >= 0) {
line = '| Conf files:';
col = 0;
workspaceStats.configFiles.forEach((item) => {
appendAndWrap(item.name, item.count);
});
output.push(line);
}
if (workspaceStats.launchConfigFiles.length > 0) {
let line = '| Launch Configs:';
workspaceStats.launchConfigFiles.forEach(each => {
const item = each.count > 1 ? ` ${each.name}(${each.count})` : ` ${each.name}`;
line += item;
});
output.push(line);
}
return output.join('\n');
}
private expandGPUFeatures(gpuFeatures: any): string {
const longestFeatureName = Math.max(...Object.keys(gpuFeatures).map(feature => feature.length));
// Make columns aligned by adding spaces after feature name
return Object.keys(gpuFeatures).map(feature => `${feature}: ${repeat(' ', longestFeatureName - feature.length)} ${gpuFeatures[feature]}`).join('\n ');
}
private formatWorkspaceMetadata(info: IMainProcessInfo): Promise<string> {
const output: string[] = [];
const workspaceStatPromises: Promise<void>[] = [];
info.windows.forEach(window => {
if (window.folderURIs.length === 0 || !!window.remoteAuthority) {
return;
}
output.push(`| Window (${window.title})`);
window.folderURIs.forEach(uriComponents => {
const folderUri = URI.revive(uriComponents);
if (folderUri.scheme === 'file') {
const folder = folderUri.fsPath;
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(stats => {
let countMessage = `${stats.fileCount} files`;
if (stats.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
output.push(`| Folder (${basename(folder)}): ${countMessage}`);
output.push(this.formatWorkspaceStats(stats));
}).catch(error => {
output.push(`| Error: Unable to collect workspace stats for folder ${folder} (${error.toString()})`);
}));
} else {
output.push(`| Folder (${folderUri.toString()}): Workspace stats not available.`);
}
});
});
return Promise.all(workspaceStatPromises)
.then(_ => output.join('\n'))
.catch(e => `Unable to collect workspace stats: ${e}`);
}
private formatProcessList(info: IMainProcessInfo, rootProcess: ProcessItem): string {
const mapPidToWindowTitle = new Map<number, string>();
info.windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
const output: string[] = [];
output.push('CPU %\tMem MB\t PID\tProcess');
if (rootProcess) {
this.formatProcessItem(info.mainPID, mapPidToWindowTitle, output, rootProcess, 0);
}
return output.join('\n');
}
private formatProcessItem(mainPid: number, mapPidToWindowTitle: Map<number, string>, output: string[], item: ProcessItem, indent: number): void {
const isRoot = (indent === 0);
const MB = 1024 * 1024;
// Format name with indent
let name: string;
if (isRoot) {
name = item.pid === mainPid ? `${product.applicationName} main` : 'remote agent';
} else {
name = `${repeat(' ', indent)} ${item.name}`;
if (item.name === 'window') {
name = `${name} (${mapPidToWindowTitle.get(item.pid)})`;
}
}
const memory = process.platform === 'win32' ? item.mem : (osLib.totalmem() * (item.mem / 100));
output.push(`${pad(Number(item.load.toFixed(0)), 5, ' ')}\t${pad(Number((memory / MB).toFixed(0)), 6, ' ')}\t${pad(Number((item.pid).toFixed(0)), 6, ' ')}\t${name}`);
// Recurse into children if any
if (Array.isArray(item.children)) {
item.children.forEach(child => this.formatProcessItem(mainPid, mapPidToWindowTitle, output, child, indent + 1));
}
}
public async reportWorkspaceStats(workspace: IWorkspace): Promise<void> {
workspace.folders.forEach(folder => {
const folderUri = URI.revive(folder.uri);
if (folderUri.scheme === 'file') {
const folder = folderUri.fsPath;
collectWorkspaceStats(folder, ['node_modules', '.git']).then(stats => {
/* __GDPR__
"workspace.stats" : {
"fileTypes" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"configTypes" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"launchConfigs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
}
*/
this.telemetryService.publicLog('workspace.stats', {
fileTypes: stats.fileTypes,
configTypes: stats.configFiles,
launchConfigs: stats.launchConfigFiles
});
}).catch(_ => {
// Report nothing if collecting metadata fails.
});
}
});
}
}

View file

@ -13,6 +13,7 @@ export interface ParsedArgs {
_urls?: string[];
help?: boolean;
version?: boolean;
telemetry?: boolean;
status?: boolean;
wait?: boolean;
waitMarkerFilePath?: string;
@ -69,6 +70,7 @@ export interface ParsedArgs {
remote?: string;
'disable-user-env-probe'?: boolean;
'enable-remote-auto-shutdown'?: boolean;
'disable-inspect'?: boolean;
}
export const IEnvironmentService = createDecorator<IEnvironmentService>('environmentService');

View file

@ -8,7 +8,8 @@ import * as os from 'os';
import { localize } from 'vs/nls';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { join } from 'vs/base/common/path';
import { writeFileSync } from 'vs/base/node/pfs';
import { statSync, readFileSync } from 'fs';
import { writeFileSync, readdirSync } from 'vs/base/node/pfs';
/**
* This code is also used by standalone cli's. Avoid adding any other dependencies.
@ -41,6 +42,7 @@ export const options: Option[] = [
{ id: 'user-data-dir', type: 'string', cat: 'o', args: 'dir', description: localize('userDataDir', "Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.") },
{ id: 'version', type: 'boolean', cat: 'o', alias: 'v', description: localize('version', "Print version.") },
{ id: 'help', type: 'boolean', cat: 'o', alias: 'h', description: localize('help', "Print usage.") },
{ id: 'telemetry', type: 'boolean', cat: 'o', description: localize('telemetry', "Shows all telemetry events which VS code collects.") },
{ id: 'folder-uri', type: 'string', cat: 'o', args: 'uri', description: localize('folderUri', "Opens a window with given folder uri(s)") },
{ id: 'file-uri', type: 'string', cat: 'o', args: 'uri', description: localize('fileUri', "Opens a window with given file uri(s)") },
@ -217,6 +219,41 @@ export function buildVersionMessage(version: string | undefined, commit: string
return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`;
}
export function buildTelemetryMessage(appRoot: string, extensionsPath: string): string {
// Gets all the directories inside the extension directory
const dirs = readdirSync(extensionsPath).filter(files => {
// This handles case where broken symbolic links can cause statSync to throw and error
try {
return statSync(join(extensionsPath, files)).isDirectory();
} catch {
return false;
}
});
const telemetryJsonFolders: string[] = [];
dirs.forEach((dir) => {
const files = readdirSync(join(extensionsPath, dir)).filter(file => file === 'telemetry.json');
// We know it contains a telemetry.json file so we add it to the list of folders which have one
if (files.length === 1) {
telemetryJsonFolders.push(dir);
}
});
const mergedTelemetry = Object.create(null);
// Simple function to merge the telemetry into one json object
const mergeTelemetry = (contents: string, dirName: string) => {
const telemetryData = JSON.parse(contents);
mergedTelemetry[dirName] = telemetryData;
};
telemetryJsonFolders.forEach((folder) => {
const contents = readFileSync(join(extensionsPath, folder, 'telemetry.json')).toString();
mergeTelemetry(contents, folder);
});
let contents = readFileSync(join(appRoot, 'telemetry-core.json')).toString();
mergeTelemetry(contents, 'vscode-core');
contents = readFileSync(join(appRoot, 'telemetry-extensions.json')).toString();
mergeTelemetry(contents, 'vscode-extensions');
return JSON.stringify(mergedTelemetry, null, 4);
}
/**
* Converts an argument into an array
* @param arg a argument value. Can be undefined, an entry or an array

View file

@ -294,7 +294,7 @@ export function parseSearchPort(args: ParsedArgs, isBuild: boolean): IDebugParam
return parseDebugPort(args['inspect-search'], args['inspect-brk-search'], 5876, isBuild);
}
export function parseDebugPort(debugArg: string | undefined, debugBrkArg: string | undefined, defaultBuildPort: number, isBuild: boolean, debugId?: string): IExtensionHostDebugParams {
function parseDebugPort(debugArg: string | undefined, debugBrkArg: string | undefined, defaultBuildPort: number, isBuild: boolean, debugId?: string): IExtensionHostDebugParams {
const portStr = debugBrkArg || debugArg;
const port = Number(portStr) || (!isBuild ? defaultBuildPort : null);
const brk = port ? Boolean(!!debugBrkArg) : false;

View file

@ -196,8 +196,8 @@ export interface IExtensionManagementService {
zip(extension: ILocalExtension): Promise<URI>;
unzip(zipLocation: URI, type: ExtensionType): Promise<IExtensionIdentifier>;
install(vsix: URI): Promise<IExtensionIdentifier>;
installFromGallery(extension: IGalleryExtension): Promise<void>;
install(vsix: URI): Promise<ILocalExtension>;
installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension>;
uninstall(extension: ILocalExtension, force?: boolean): Promise<void>;
reinstallFromGallery(extension: ILocalExtension): Promise<void>;
getInstalled(type?: ExtensionType): Promise<ILocalExtension[]>;

View file

@ -4,14 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionGalleryService, InstallOperation } from '../common/extensionManagement';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
import { cloneAndChange } from 'vs/base/common/objects';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ILogService } from 'vs/platform/log/common/log';
function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI {
return URI.revive(transformer ? transformer.transformIncoming(uri) : uri);
@ -82,9 +80,6 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
constructor(
private readonly channel: IChannel,
private readonly remote: boolean,
private readonly galleryService: IExtensionGalleryService,
private readonly logService: ILogService
) { }
get onInstallExtension(): Event<InstallExtensionEvent> { return this.channel.listen('onInstallExtension'); }
@ -100,29 +95,12 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
return Promise.resolve(this.channel.call('unzip', [zipLocation, type]));
}
install(vsix: URI): Promise<IExtensionIdentifier> {
return Promise.resolve(this.channel.call('install', [vsix]));
install(vsix: URI): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('install', [vsix])).then(local => transformIncomingExtension(local, null));
}
async installFromGallery(extension: IGalleryExtension): Promise<void> {
try {
await Promise.resolve(this.channel.call('installFromGallery', [extension]));
} catch (error) {
if (this.remote) {
try {
const compatible = await this.galleryService.getCompatibleExtension(extension);
if (compatible) {
const installed = await this.getInstalled(ExtensionType.User);
const location = await this.galleryService.download(compatible, installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0] ? InstallOperation.Update : InstallOperation.Install);
await this.install(URI.file(location));
return;
}
} catch (e) {
this.logService.error(e);
}
}
throw error;
}
installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('installFromGallery', [extension])).then(local => transformIncomingExtension(local, null));
}
uninstall(extension: ILocalExtension, force = false): Promise<void> {

View file

@ -109,7 +109,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
private uninstalledFileLimiter: Queue<any>;
private reportedExtensions: Promise<IReportedExtension[]> | undefined;
private lastReportTimestamp = 0;
private readonly installingExtensions: Map<string, CancelablePromise<void>> = new Map<string, CancelablePromise<void>>();
private readonly installingExtensions: Map<string, CancelablePromise<ILocalExtension>> = new Map<string, CancelablePromise<ILocalExtension>>();
private readonly uninstallingExtensions: Map<string, CancelablePromise<void>> = new Map<string, CancelablePromise<void>>();
private readonly manifestCache: ExtensionsManifestCache;
private readonly extensionLifecycle: ExtensionsLifecycle;
@ -158,7 +158,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
unzip(zipLocation: URI, type: ExtensionType): Promise<IExtensionIdentifier> {
this.logService.trace('ExtensionManagementService#unzip', zipLocation.toString());
return this.install(zipLocation, type);
return this.install(zipLocation, type).then(local => local.identifier);
}
private collectFiles(extension: ILocalExtension): Promise<IFile[]> {
@ -187,7 +187,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
}
install(vsix: URI, type: ExtensionType = ExtensionType.User): Promise<IExtensionIdentifier> {
install(vsix: URI, type: ExtensionType = ExtensionType.User): Promise<ILocalExtension> {
this.logService.trace('ExtensionManagementService#install', vsix.toString());
return createCancelablePromise(token => {
return this.downloadVsix(vsix).then(downloadLocation => {
@ -222,7 +222,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
metadata => this.installFromZipPath(identifierWithVersion, zipPath, metadata, type, operation, token),
() => this.installFromZipPath(identifierWithVersion, zipPath, null, type, operation, token))
.then(
() => { this.logService.info('Successfully installed the extension:', identifier.id); return identifier; },
local => { this.logService.info('Successfully installed the extension:', identifier.id); return local; },
e => {
this.logService.error('Failed to install the extension:', identifier.id, e.message);
return Promise.reject(e);
@ -264,7 +264,10 @@ export class ExtensionManagementService extends Disposable implements IExtension
));
}
async installFromGallery(extension: IGalleryExtension): Promise<void> {
async installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension> {
if (!this.galleryService.isEnabled()) {
return Promise.reject(new Error(nls.localize('MarketPlaceDisabled', "Marketplace is not enabled")));
}
const startTime = new Date().getTime();
const onDidInstallExtensionSuccess = (extension: IGalleryExtension, operation: InstallOperation, local: ILocalExtension) => {
@ -298,7 +301,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
this._onInstallExtension.fire({ identifier: extension.identifier, gallery: extension });
let operation: InstallOperation = InstallOperation.Install;
let cancellationToken: CancellationToken, successCallback: (a?: any) => void, errorCallback: (e?: any) => any | null;
let cancellationToken: CancellationToken, successCallback: (local: ILocalExtension) => void, errorCallback: (e?: any) => any | null;
cancellablePromise = createCancelablePromise(token => { cancellationToken = token; return new Promise((c, e) => { successCallback = c; errorCallback = e; }); });
this.installingExtensions.set(key, cancellablePromise);
try {
@ -320,7 +323,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
}
this.installingExtensions.delete(key);
onDidInstallExtensionSuccess(extension, operation, local);
successCallback(null);
successCallback(local);
},
error => {
this.installingExtensions.delete(key);
@ -450,7 +453,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
}
this.logService.info('Installation completed.', identifier.id);
if (metadata) {
local.metadata = metadata;
this.setMetadata(local, metadata);
return this.saveMetadataForLocalExtension(local);
}
return local;
@ -780,12 +783,21 @@ export class ExtensionManagementService extends Disposable implements IExtension
const readmeUrl = readme ? URI.file(path.join(extensionPath, readme)) : null;
const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0];
const changelogUrl = changelog ? URI.file(path.join(extensionPath, changelog)) : null;
const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name), uuid: metadata ? metadata.id : null };
return <ILocalExtension>{ type, identifier, manifest, metadata, location: URI.file(extensionPath), readmeUrl, changelogUrl };
const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
const local = <ILocalExtension>{ type, identifier, manifest, metadata, location: URI.file(extensionPath), readmeUrl, changelogUrl };
if (metadata) {
this.setMetadata(local, metadata);
}
return local;
}))
.then(undefined, () => null);
}
private setMetadata(local: ILocalExtension, metadata: IGalleryMetadata): void {
local.metadata = metadata;
local.identifier.uuid = metadata.id;
}
async removeDeprecatedExtensions(): Promise<void> {
await this.removeUninstalledExtensions();
await this.removeOutdatedExtensions();

View file

@ -208,7 +208,7 @@ export interface IFileSystemProvider {
readonly capabilities: FileSystemProviderCapabilities;
readonly onDidChangeCapabilities: Event<void>;
readonly onDidErrorOccur?: Event<Error>; // TODO@ben remove once file watchers are solid
readonly onDidErrorOccur?: Event<string>; // TODO@ben remove once file watchers are solid
readonly onDidChangeFile: Event<IFileChange[]>;
watch(resource: URI, opts: IWatchOptions): IDisposable;

View file

@ -9,14 +9,13 @@ import { parseArgs } from 'vs/platform/environment/node/argv';
import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/common/issue';
import { BrowserWindow, ipcMain, screen, Event, dialog } from 'electron';
import { ILaunchService } from 'vs/platform/launch/electron-main/launchService';
import { PerformanceInfo, IDiagnosticsService } from 'vs/platform/diagnostics/electron-main/diagnosticsService';
import { PerformanceInfo, IDiagnosticsService, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IWindowState } from 'vs/platform/windows/electron-main/windows';
import { listProcesses } from 'vs/base/node/ps';
import { isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
const DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
@ -40,10 +39,14 @@ export class IssueService implements IIssueService {
}
private registerListeners(): void {
ipcMain.on('vscode:issueSystemInfoRequest', (event: Event) => {
this.diagnosticsService.getSystemInfo(this.launchService).then(msg => {
event.sender.send('vscode:issueSystemInfoResponse', msg);
});
ipcMain.on('vscode:issueSystemInfoRequest', async (event: Event) => {
Promise.all([this.launchService.getMainProcessInfo(), this.launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })])
.then(result => {
const [info, remoteData] = result;
this.diagnosticsService.getSystemInfo(info, remoteData).then(msg => {
event.sender.send('vscode:issueSystemInfoResponse', msg);
});
});
});
ipcMain.on('vscode:listProcesses', async (event: Event) => {
@ -262,8 +265,12 @@ export class IssueService implements IIssueService {
});
}
public getSystemStatus(): Promise<string> {
return this.diagnosticsService.getDiagnostics(this.launchService);
public async getSystemStatus(): Promise<string> {
return Promise.all([this.launchService.getMainProcessInfo(), this.launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })])
.then(result => {
const [info, remoteData] = result;
return this.diagnosticsService.getDiagnostics(info, remoteData);
});
}
private getWindowPosition(parentWindow: BrowserWindow, defaultWidth: number, defaultHeight: number): IWindowState {
@ -335,14 +342,18 @@ export class IssueService implements IIssueService {
}
private getPerformanceInfo(): Promise<PerformanceInfo> {
return new Promise((resolve, reject) => {
this.diagnosticsService.getPerformanceInfo(this.launchService)
.then(diagnosticInfo => {
resolve(diagnosticInfo);
})
.catch(err => {
this.logService.warn('issueService#getPerformanceInfo ', err.message);
reject(err);
return new Promise(async (resolve, reject) => {
Promise.all([this.launchService.getMainProcessInfo(), this.launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true })])
.then(result => {
const [info, remoteData] = result;
this.diagnosticsService.getPerformanceInfo(info, remoteData)
.then(diagnosticInfo => {
resolve(diagnosticInfo);
})
.catch(err => {
this.logService.warn('issueService#getPerformanceInfo ', err.message);
reject(err);
});
});
});
}

View file

@ -0,0 +1,21 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { UriComponents } from 'vs/base/common/uri';
export interface IWindowInfo {
pid: number;
title: string;
folderURIs: UriComponents[];
remoteAuthority?: string;
}
export interface IMainProcessInfo {
mainPID: number;
// All arguments after argv[0], the exec path
mainArguments: string[];
windows: IWindowInfo[];
screenReader: boolean;
gpuFeatureStatus: any;
}

View file

@ -14,12 +14,13 @@ import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-m
import { whenDeleted } from 'vs/base/node/pfs';
import { IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { URI, UriComponents } from 'vs/base/common/uri';
import { BrowserWindow, ipcMain, Event as IpcEvent } from 'electron';
import { URI } from 'vs/base/common/uri';
import { BrowserWindow, ipcMain, Event as IpcEvent, app } from 'electron';
import { Event } from 'vs/base/common/event';
import { hasArgs } from 'vs/platform/environment/node/argv';
import { coalesce } from 'vs/base/common/arrays';
import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
import { IMainProcessInfo, IWindowInfo } from 'vs/platform/launch/common/launchService';
export const ID = 'launchService';
export const ILaunchService = createDecorator<ILaunchService>(ID);
@ -29,20 +30,6 @@ export interface IStartArguments {
userEnv: IProcessEnvironment;
}
export interface IWindowInfo {
pid: number;
title: string;
folderURIs: UriComponents[];
remoteAuthority?: string;
}
export interface IMainProcessInfo {
mainPID: number;
// All arguments after argv[0], the exec path
mainArguments: string[];
windows: IWindowInfo[];
}
export interface IRemoteDiagnosticOptions {
includeProcesses?: boolean;
includeWorkspaceMetadata?: boolean;
@ -280,7 +267,9 @@ export class LaunchService implements ILaunchService {
return Promise.resolve({
mainPID: process.pid,
mainArguments: process.argv.slice(1),
windows
windows,
screenReader: app.isAccessibilitySupportEnabled(),
gpuFeatureStatus: app.getGPUFeatureStatus()
});
}

View file

@ -20,15 +20,7 @@ export interface IProgressService {
withProgress<R = any>(options: IProgressOptions | IProgressNotificationOptions | IProgressCompositeOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: () => void): Promise<R>;
}
export const ILocalProgressService = createDecorator<ILocalProgressService>('localProgressService');
/**
* A progress service that will report progress local to the UI piece triggered from. E.g.
* if used from an action of a viewlet, the progress will be reported in that viewlet.
*/
export interface ILocalProgressService {
_serviceBrand: ServiceIdentifier<ILocalProgressService>;
export interface IProgressIndicator {
/**
* Show progress customized with the provided flags.
@ -132,7 +124,7 @@ export class LongRunningOperation extends Disposable {
private currentProgressTimeout: any;
constructor(
private localProgressService: ILocalProgressService
private progressIndicator: IProgressIndicator
) {
super();
}
@ -147,7 +139,7 @@ export class LongRunningOperation extends Disposable {
const newOperationToken = new CancellationTokenSource();
this.currentProgressTimeout = setTimeout(() => {
if (newOperationId === this.currentOperationId) {
this.currentProgressRunner = this.localProgressService.show(true);
this.currentProgressRunner = this.progressIndicator.show(true);
}
}, progressDelay);
@ -173,3 +165,13 @@ export class LongRunningOperation extends Disposable {
}
}
}
export const IEditorProgressService = createDecorator<IEditorProgressService>('editorProgressService');
/**
* A progress service that will report progress local to the editor triggered from.
*/
export interface IEditorProgressService extends IProgressIndicator {
_serviceBrand: ServiceIdentifier<IEditorProgressService>;
}

View file

@ -27,6 +27,9 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF
private readonly _onDidChange = this._register(new Emitter<IFileChange[]>());
readonly onDidChangeFile: Event<IFileChange[]> = this._onDidChange.event;
private _onDidWatchErrorOccur: Emitter<string> = this._register(new Emitter<string>());
get onDidErrorOccur(): Event<string> { return this._onDidWatchErrorOccur.event; }
private readonly _onDidChangeCapabilities = this._register(new Emitter<void>());
readonly onDidChangeCapabilities: Event<void> = this._onDidChangeCapabilities.event;
@ -43,8 +46,14 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF
}
private registerListeners(): void {
this._register(this.channel.listen<IFileChangeDto[]>('filechange', [this.session])((events) => {
this._onDidChange.fire(events.map(event => ({ resource: URI.revive(event.resource), type: event.type })));
this._register(this.channel.listen<IFileChangeDto[] | string>('filechange', [this.session])((eventsOrError) => {
if (Array.isArray(eventsOrError)) {
const events = eventsOrError;
this._onDidChange.fire(events.map(event => ({ resource: URI.revive(event.resource), type: event.type })));
} else {
const error = eventsOrError;
this._onDidWatchErrorOccur.fire(error);
}
}));
}

View file

@ -179,6 +179,7 @@ const configurationValueWhitelist = [
'terminal.integrated.fontFamily',
'window.openFilesInNewWindow',
'window.restoreWindows',
'window.nativeFullScreen',
'window.zoomLevel',
'workbench.editor.enablePreview',
'workbench.editor.enablePreviewFromQuickOpen',

View file

@ -41,7 +41,6 @@ configurationRegistry.registerConfiguration({
scope: ConfigurationScope.APPLICATION,
title: localize('enableWindowsBackgroundUpdatesTitle', "Enable Background Updates on Windows"),
description: localize('enableWindowsBackgroundUpdates', "Enable to download and install new VS Code Versions in the background on Windows"),
tags: ['usesOnlineServices'],
included: isWindows
},
'update.showReleaseNotes': {

View file

@ -153,7 +153,7 @@ export interface IWindowsService {
// Global methods
openWindow(windowId: number, uris: IURIToOpen[], options: IOpenSettings): Promise<void>;
openNewWindow(options?: INewWindowOptions): Promise<void>;
openExtensionDevelopmentHostWindow(args: ParsedArgs): Promise<void>;
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void>;
getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>;
getWindowCount(): Promise<number>;
log(severity: string, ...messages: string[]): Promise<void>;
@ -300,7 +300,7 @@ export function getTitleBarStyle(configurationService: IConfigurationService, en
return 'native'; // native tabs on sierra do not work with custom title style
}
const useSimpleFullScreen = isMacintosh && configuration.nativeFullScreen === false;
const useSimpleFullScreen = false; //isMacintosh && configuration.nativeFullScreen === false;
if (useSimpleFullScreen) {
return 'native'; // simple fullscreen does not work well with custom title style (https://github.com/Microsoft/vscode/issues/63291)
}

View file

@ -12,6 +12,7 @@ import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { URI } from 'vs/base/common/uri';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { IProcessEnvironment } from 'vs/base/common/platform';
export class WindowsService implements IWindowsService {
@ -195,8 +196,8 @@ export class WindowsService implements IWindowsService {
return this.channel.call('openNewWindow', options);
}
openExtensionDevelopmentHostWindow(args: ParsedArgs): Promise<void> {
return this.channel.call('openExtensionDevelopmentHostWindow', args);
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
return this.channel.call('openExtensionDevelopmentHostWindow', [args, env]);
}
async getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {

View file

@ -21,7 +21,7 @@ import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platf
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { Schemas } from 'vs/base/common/network';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { isMacintosh, isLinux } from 'vs/base/common/platform';
import { isMacintosh, isLinux, IProcessEnvironment } from 'vs/base/common/platform';
import { ILogService } from 'vs/platform/log/common/log';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
@ -306,13 +306,14 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH
this.windowsMainService.openNewWindow(OpenContext.API, options);
}
async openExtensionDevelopmentHostWindow(args: ParsedArgs): Promise<void> {
async openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
this.logService.trace('windowsService#openExtensionDevelopmentHostWindow ' + JSON.stringify(args));
if (args.extensionDevelopmentPath) {
this.windowsMainService.openExtensionDevelopmentHostWindow(args.extensionDevelopmentPath, {
context: OpenContext.API,
cli: args
cli: args,
userEnv: Object.keys(env).length > 0 ? env : undefined
});
}
}

View file

@ -102,7 +102,7 @@ export class WindowsChannel implements IServerChannel {
return this.service.openWindow(arg[0], urisToOpen, options);
}
case 'openNewWindow': return this.service.openNewWindow(arg);
case 'openExtensionDevelopmentHostWindow': return this.service.openExtensionDevelopmentHostWindow(arg);
case 'openExtensionDevelopmentHostWindow': return this.service.openExtensionDevelopmentHostWindow(arg[0], arg[1]);
case 'getWindows': return this.service.getWindows();
case 'getWindowCount': return this.service.getWindowCount();
case 'relaunch': return this.service.relaunch(arg[0]);

View file

@ -185,7 +185,11 @@ export class Workspace implements IWorkspace {
return null;
}
return this._foldersMap.findSubstr(resource.toString()) || null;
return this._foldersMap.findSubstr(resource.with({
scheme: resource.scheme,
authority: resource.authority,
path: resource.path
}).toString()) || null;
}
private updateFoldersMap(): void {

Some files were not shown because too many files have changed in this diff Show more